In a previous post exploring rounded corner methods, I covered a technique using absolute positioning for faking rounded corners in browsers greater than IE6. One issue with faking rounded corners is the amount of HTML markup required as well as the hassle of crafting the accompanying CSS. I have created a jQuery plug-in for adding the required markup and a complementary Sass/Compass @mixin for generating the required CSS. The markup generated utilizes jQuery UI theming for the CSS class names. The code is available on GitHub
Summary of the Technique
As covered before, the idea is to use extra markup and CSS to create rounded corners even without support for border-radius
. Of course the technique is also useful for creating fancy corners that border-radius
wouldn't support. The two examples below show a normal div
using border-radius
and a box that is using the absolutely positioned span
technique from the previous article.
Basic Markup
The absolute positioning technique requires some additional markup to be added to the page for the corners and sides of the box. Below the initial .box
is shown with no additional markup.
|
In order to create the illusion of corners, some additional markup must be added to the page. First the content is wrapped in a .ui-corners-content
that is used with z-index
to ensure that the corners never cover up the content of our .box
— border-radius
doesn't clip content unless overflow: hidden;
is set. Next, eight span
s are added; one for each corner and side. Below is the markup used for creating the rounded corner illusion.
|
As you can see above, the extra markup is very straightforward but it's not exactly ideal to have to add this to every box on a website — this is the point of the jQuery plug-in that will be discussed further down.
Basic CSS
In order to optimize performance and simplify the JavaScript plug-in, all of the styling is done using CSS. The base CSS will set the z-index
of the .ui-corners-content
and position each of the corners and sides. As mentioned in the previous article, conflicting positioning properties are used to ensure that the sides stretch the fill width of the .box
. For instance the left side, .ui-corners-side-left
, is given a top
and a bottom
of 10px. Setting the top
and bottom
at the same time has the effect of stretching the span
the entire height because both properties are honored. The 10px spacing is to prevent the sides from overlapping the corners. As mentioned in the previous article, IE6 will ignore the conflicting properties which makes this a poor solution for sites that require IE6 support.
The CSS below will correctly position all of the span
s and set some default heights and widths. In order to actually see something, the base CSS needs to be extended by adding background images and altering the default heights and widths — this is the point of the Compass @mixin
that will be discussed further down.
|
Although absolutely positioned background images can look like a native border-radius
, they don't actually affect the sizing of the box like a real border does. It's easy to fake the presence of a border by adding padding
to the .box
equal to the width of the border. While it's possible to simply set a transparent border — border: 10px solid transparent;
— setting a border will require additional calculations for the corner and side span
s because border appears outside the box.
Using the jQuery Corners Plug-in
The jQuery Corners plug-in is very straightforward. Exactly as described in the basic markup section above, it wraps the content of the container in a div
and adds eight span
s to the container. Again, starting with the basic box.html file in the basic markup section above, the additional markup can be added as shown below.
|
Currently the plug-in takes no arguments and does not apply any styling to the page. This is intentional because the styling should be controlled using CSS, similar to most jQuery UI widgets.
The Actual Plug-In
Below is the actual plug-in that adds the markup to the page. As noted above, the plug-in wraps the contents of the target element in a .ui-corners-content
and then appends all of the side and corner span
s.
|
Special care is taken to avoid adding the extra markup to elements that have already been processed. The .ui-corners
class is detected and those elements are skipped. Also, repeated strings are saved in variables to aid in compressing. The script is only 402 characters after running it through YUI Compressor and 267 bytes after gzipping.
Seeing the Plug-in In Action
Below you can see a .box
that has had the corners applied. The base.css file shown above is used for the styling. Background colors have been applied to the side and corner span
s to make them visible. It's also clear that the corners and sides are not overlapping the content.
For more advanced styling it is recommended to use the SASS @mixin
described below.
Using the UI Corners @mixin
Although the base.css above will correctly position all of the corners and sides, more calculations are needed for actually using background images. For these purposes the SASS/Compass plug-in provides two @mixin
s: corner-images
and corner-border-width
. These @mixin
s greatly simplify the creation of CSS for mimicking rounded corners as well as more advanced examples.
Using @mixin corner-images
The corner-images
@mixin
takes eight arguments, one for each corner and side. The arguments are ordered clockwise starting with the top-left corner and ending with the left side. Each argument is a Sass list of values. The corners and sides require slightly different values in the list — corners have a height and width while sides only have one dimension that can be specified — however background-image
value is always the first value. All other values in the list can be left at default. Each argument is optional and may be skipped by passing in "auto" or using Sass keyword arguments.
@include corner-images( [$tl], [$t], [$tr], [$r], [$br], [$b], [$bl], [$l] )
$tl
— [background-image] [width] [height] [background-position-x] [background-position-y] [left] [top]$t
— [background-image] [height] [background-position-x] [background-position-y] [top] [left] [right]$tr
— [background-image] [width] [height] [background-position-x] [background-position-y] [right] [top]$r
— [background-image] [width] [background-position-x] [background-position-y] [right] [top] [bottom]$br
— [background-image] [width] [height] [background-position-x] [background-position-y] [right] [bottom]$b
— [background-image] [height] [background-position-x] [background-position-y] [bottom] [left] [right]$bl
— [background-image] [width] [height] [background-position-x] [background-position-y] [left] [bottom]$l
— [background-image] [width] [background-position-x] [background-position-y] [left] [top] [bottom]
Using @mixin corner-border-width
The corner-border-width
@mixin
mimics a real border on the box
using padding. As discussed above, setting a transparent border will cause some positioning issues because borders appears outside of the element. This issues is overcome by simply using padding
. For convenience, if real padding is needed it can be passed as the second argument which will be added to the first argument. Both arguments are Sass lists taking the same values as the CSS padding property. Similar to padding
, each argument can take a list of one, two, three or four values.
@include corner-border-width( $border-width, [$padding] )
$border-width
— [top-width] [right-width] [bottom-width] [left-width]$padding
— [top-width] [right-width] [bottom-width] [left-width]
The Actual @mixin
Below is the entire @mixin
that is used for generating the CSS. There are the two mixins mentioned above as well as a number of helper functions for manipulation all of the list values. Close inspection reveals that there are a number over default variables available. Passing "default" instead of "auto" for any value will favor the default value if it exists. Auto values are based on the other passed values while default values rely blindly on the default variables. The default variables can be easily overridden. At the bottom of the file, the default styles are visible. Simply including this plugin will generate the default styles as shown in the base.css above.
|
Basic Fake border-radius
Example
In order to mimic border-radius
we'll need some images. For this example we'll use eight separate images as described in the previous article. Using the @mixin
this becomes very simple as shown below.
|
Above is a .box
where an image is used for each corner and side. The .box
also has a border-width
of 1px and padding
of 10px. Below is the CSS code that is generated. Only the code that is distinct form the basic CSS is generated. The "?1313871969" after the images is a cache busting artifact caused by the @mixin
s reliance on Compass's image-url
@function
and can be turned off by setting the global $ui-corners-cache-buster
variable to false.
|
One important thing to note is that the images are all measured using the Compass image dimension functions. Because all of list values other than [background-image]
were left to auto, the corners were given a height and width equal to their respective background images. Similarly the sides were given values based on the images. For instance, the left side was given a top
equal to the hight of the top-left image, a bottom
equal to the hight of the bottom-left image and a width equal to the width of the top-left image. By default the sides are given the respective width or height of the nearest corner instead of the height width of their own image. This will help in cases where background colors also need to be applied to the sides to match the desired design.
Basic Sprite Example
Of course include eight separate images just to mimic border-radius
isn't most appealing thing in the world — sprites are a good thing. Currently the sprite needs to be produced beforehand and cannot be generated with Compass's excellent sprite functions. The sprite image from the previous article will be used.
|
In the example above the same image is passed in for each of the corners and sides. For each corner a width
, height
, background-position-x
and background-position-y
are supplied. For the sides the respective height
or width
is specified as "auto" and then background-position-x
and background-position-y
are supplied. The above example will generate the CSS below.
|
Similar to the basic example above, only the rules that differ from the basic.css are generated. When values are identical for groups of selectors they are appropriately grouped. For instance, the background-image
is only specified once. Also of note, the background-position
is no longer the default and is now in the CSS.
Using a sprite in this example will significantly reduce the file sizes. The eight images together total 4.4KB while the sprite image is only 1.1KB. Of course this also removes eight HTTP requests which is always a good thing — ask Google.
Fancy Sprite Example
Of course, this technique is not limited by simply mimicking border-radius
. It's also possible to apply fancier borders that CSS could never do. For instance, imagine creating a box where nearly every Photoshop Layer Style has been applied — Drop Shadow, Inner Shadow, Outer Glow, Inner Glow, Bevel and Emboss and Color Overlay. It would be hard to mimick that without using images.
Above is an image created using the list of Photoshop filters listed above. It has been turned into two different sprites. It's not possible to use a single sprite for all eight corners and sides when the sides are more that 1px solid colors. The top and bottom sides are repeated above and below the corners in the sprite.
|
In the above Sass, the positioning values are also used to move the shadow and glow outside the original box. For instance, the top-left corner is the first argument in corner-images
and the first item in the list is the fancy sprite. The top left corner image is 18px by 18px and starts at 0px by 18px within the sprite. The first 8px of the corner are actually shadow as are the top 4px. The similar measurements are done for all of the corners and sides. The right and left sides get their own sprite because they didn't fit in the other one. This generates the CSS below.
|
Below you can see the fancy sprite corners in a live example. It is important to note that the CSS will scale with the box as its content grows. The generated CSS would apply to any size box without any alterations.