{"id":2536,"date":"2011-03-29T00:18:55","date_gmt":"2011-03-29T04:18:55","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=2536"},"modified":"2012-08-31T15:01:08","modified_gmt":"2012-08-31T19:01:08","slug":"pixel-perfect-css3-border-image-in-depth","status":"publish","type":"post","link":"https:\/\/www.useragentman.com\/blog\/2011\/03\/29\/pixel-perfect-css3-border-image-in-depth\/","title":{"rendered":"Pixel Perfect CSS3 <code>border-image<\/code> In Depth."},"content":{"rendered":"<div id=\"introExample\" class=\"alignLeft\">\n<p>This is an example of CSS3 <code>border-image<\/code> in action. Browsers that don&#8217;t support it will see a normal solid coloured <code>border<\/code>, while modern browsers will see a nice framed <code>border-image<\/code>. Note that the clouds are produced with an additional <code>background-image<\/code>, showing the possibility of having separate images for borders and backgrounds.<\/p>\n<\/div>\n<p>The <code>border-image<\/code> property is something I&#8217;ve been wanting for a long time. For years, I have been cutting up images into several pieces in order to emulate this effect (the most recent example of this was used in <a href=\"\/tests\/fontConverter\/ArgBiwSc.html\">this demo<\/a> of the <a href=\"\/blog\/2011\/02\/20\/converting-font-face-fonts-quickly-in-any-os\/\">CSS3 Font Converter<\/a>).  The difference is that <strong>CSS3&#8217;s border-image property uses only one image and two lines of CSS<\/strong> (well &#8230; 6 if you include the vendor-specific properties and the fallback for browsers that don&#8217;t support it).<\/p>\n<p>Since it is newly implemented in most web browsers, there are a few gotchas that developers should be aware of before implementing <code>border-image<\/code>.  This article will cover these caveats, a tool that you can use to help generate border-images effectively, and a few things you should keep in mind so that pages don&#8217;t look funny in browsers that don&#8217;t support <code>border-radius<\/code>.  <\/p>\n<h2>Let&#8217;s Look At An Example<\/h2>\n<div id=\"example1\">\n<p>This is an example of a block level element that uses the  <code>border-image<\/code> property.  The <code>border-image<\/code> is viewable in all major browsers except for IE (more on that later).  It <strong>uses only one image<\/strong> to produce the border &mdash; no images were cut-up into pieces or harmed in any other way.  The code to generate this border is fairly straight-forward once you know how it works:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n#object {\r\n \r\n   \/*\r\n    * These border widths must match the border-image numbers.\r\n    *\/\r\n    border-width: 23px 22px 22px 26px;\r\n \r\n   \/*\r\n    * Note that all browsers use their respective vendor prefix.  Also \r\n    * note that, unlike the border-width values, the widths in the \r\n    * border-image property don't have the 'px' unit at the end.\r\n    *\/\r\n   -moz-border-image:    url('image.png') 23 22 22 26 round round;\r\n   -webkit-border-image: url('image.png') 23 22 22 26 round round;\r\n   -o-border-image:      url('image.png') 23 22 22 26 round round;\r\n   border-image:         url('image.png') 23 22 22 26 round round;\r\n\r\n   \/*\r\n    * You should include a border-color and border-style as a fallback\r\n    * for browsers that don't support border-image (and to prevent \r\n    * this known issue that happens in certain versions of Firefox:\r\n    * https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=748253 (thanks to \r\n    * Lith for pointing this out).\r\n    *\/\r\n    border-color: #cccccc;\r\n    border-style: solid;\r\n }\r\n<\/pre>\n<\/blockquote>\n<div class=\"centered\">\nThe original image looks like this:<br \/>\n<img decoding=\"async\" src=\"\/border-image\/images\/borders\/chain.png\" alt=\"image of a chain\" \/><br \/>\nIt is an edited version of an image produced by <a href=\"http:\/\/www.free-printable-borders.com\/\">Free Printable Borders<\/a>.\n<\/div>\n<\/div>\n<p>Note that the image repeats to the size of the block it borders.  When you design a <code>border-image<\/code>, the border should tile in a similar way that a <code>background-image<\/code> does.  There are some major differences though, so let&#8217;s show in depth how <code>border-image<\/code> is used, and introduce you to the tool that will help even the laziest developer in the world (i.e. me) create them quickly.<\/p>\n<h2>Basic Syntax<\/h2>\n<p>Note that the basic CSS is quite easy if you know how <code>border-width<\/code> works:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n#selector {\r\n\r\n  border-width: <em>&lt;top-width&gt;<\/em>px <em>&lt;right-width&gt;<\/em>px <em>&lt;bottom-width&gt;<\/em>px <em>&lt;left-width&gt;<\/em>px;\r\n\r\n  border-image: url(<em>&lt;image-url&gt;<\/em>) <em>&lt;top-width&gt;<\/em> <em>&lt;right-width&gt;<\/em> <em>&lt;bottom-width&gt;<\/em> <em>&lt;left-width&gt;<\/em> <br \/>\r\n                <em>&lt;horizontal-effect&gt;<\/em> <em>&lt;vertical-effect&gt;<\/em>;\r\n\r\n}\r\n<\/pre>\n<\/blockquote>\n<p>Note that if you are measuring your widths in pixels, then you must put the <code>px<\/code> unit inside the <code>border-width<\/code> declaration, but you must leave it out in the <code>border-image<\/code> one.  I know it doesn&#8217;t seem logical, but it&#8217;s just the way it is.<\/p>\n<p>To illustrate the all of the <code>border-image<\/code> parameters, let&#8217;s take this image:<\/p>\n<div class=\"centered\">\n<img decoding=\"async\" src=\"\/border-image\/images\/borders\/border.png\" alt=\"image of a border\" \/>\n<\/div>\n<p>First we must grab the border widths in the right order:<\/p>\n<p><div id=\"attachment_2568\" style=\"width: 396px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/diagram.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2568\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/diagram.png\" alt=\"A diagram showing how the borders widths are ordered.\" title=\"diagram\" width=\"386\" height=\"198\" class=\"size-full wp-image-2568\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/diagram.png 386w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/diagram-300x153.png 300w\" sizes=\"auto, (max-width: 386px) 100vw, 386px\" \/><\/a><p id=\"caption-attachment-2568\" class=\"wp-caption-text\">A diagram showing how the borders widths are ordered.<\/p><\/div><\/p>\n<p>(Note that the order of the <code>border-image<\/code> widths is consistent with the order that <code>margin<\/code> and <code>padding<\/code> uses).  <\/p>\n<p>Now, let us apply effects on our image.<\/p>\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>Pure CSS Example (will be visible if your browser supports <code>border-image<\/code><\/th>\n<th>Firefox Screenshot (Opera and Webkit are similar, except for the <code>round<\/code> effect, which Chrome and Safari currently don&#8217;t support.)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<div id=\"stretchExample\" class=\"example2\">\nThis is an example of a stretched border.  Note that the square in the corner remains intact, while the other squares are the ones that stretch.\n<\/div>\n<\/td>\n<td>\n<img loading=\"lazy\" decoding=\"async\" width=\"388\" height=\"186\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/stretch.png\" alt=\"Screenshot of border-image with stretch effect.\" title=\"stretch\" class=\"alignnone size-full wp-image-2600\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/stretch.png 388w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/stretch-300x143.png 300w\" sizes=\"auto, (max-width: 388px) 100vw, 388px\" \/>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<div id=\"repeatExample\" class=\"example2\">\nThis is an example of a repeated border.   You&#8217;ll note that the browser will apply symmetry  on the border, so that it looks &#8220;balanced&#8221;.\n<\/div>\n<\/td>\n<td>\n<img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/repeat.png\" alt=\"Screenshot of border-image with repeat effect.\" title=\"repeat\" class=\"alignnone size-full wp-image-2600\" \/><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<div id=\"roundExample\" class=\"example2\">\nThis is an  example of a rounded border.  In this example, the browser tries to &#8220;round&#8221; the widths and lengths of the squares so they are not abruptly cut off.  <strong>Currently, this property is only supported by Firefox and Opera.<\/strong>\n<\/div>\n<\/td>\n<td>\n<img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/round.png\" alt=\"Screenshot of border-image with round effect.\" title=\"round\" class=\"alignnone size-full wp-image-2600\" \/>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>But I <em>Hate<\/em> Counting Pixels!<\/h2>\n<p>If you are the laziest developer in the world (i.e. me), you don&#8217;t want to crack open your graphics editor, open up a image file and count the pixels by hand &#8211; you want a tool that will generate the CSS for you.  After all, don&#8217;t we use computers so that they will do things for us?  At least, <a href=\"http:\/\/www.youtube.com\/watch?v=bBBw9E2Q_aY\">until they take over the world?<\/a><\/p>\n<p>I was in the middle of creating my own tool, but I noticed that  <a href=\"http:\/\/www.incaseofstairs.com\/\">Kevin Decker<\/a> beat me to it with his excellent <a href=\"http:\/\/www.border-image.com\/\">Border Image Generator<\/a>.  You can take any image, from the web or your desktop, drag a few sliders around, and <em>voil&aacute;!<\/em>, you have your code, vendor-prefixes and all. You should definitely check it out if you are as lazy as I am.<\/p>\n<h2>Percentage Widths<\/h2>\n<p>The <code>border-image<\/code> property can also take percentage values, which correspond to the image&#8217;s width in height.  For example, let&#8217;s take this 81&#215;81 image:<\/p>\n<div class=\"centered\">\n<img decoding=\"async\" src=\"\/border-image\/images\/borders\/chain.png\" alt=\"image of a border\" \/>\n<\/div>\n<p>As you recall, we used the following pixel dimensions:<\/p>\n<blockquote class=\"code\">\n<pre>\r\nborder-image: url('\/border-image\/images\/borders\/chain.png') 23 22 22 26 round;\r\n<\/pre>\n<\/blockquote>\n<p>If you wanted to convert the pixel widths to percentages, you must take each value and divide it by either the entire width of the <code>border-image<\/code> (for the left and right widths) or by the height of the <code>border-image<\/code> (for the top and bottom widths).  In the above case:<\/p>\n<ul>\n<li>The top border width percentage = (top border width in pixels) \/ (<code>border-image<\/code> height) = 23 \/ 81 = 0.283&#8230; = 28%<\/li>\n<li>The right border width percentage = (right border width in pixels) \/ (<code>border-image<\/code> width) = 22 \/ 81 = 0.271&#8230; = 27%<\/li>\n<li>The bottom border width percentage = (bottom border width in pixels) \/ (<code>border-image<\/code> height) = 22 \/ 81 = 0.271 = 27%<\/li>\n<li>The left border width percentage = (left border width in pixels) \/ (<code>border-image<\/code> width) = 26 \/ 81 = 0.320 = 32%<\/li>\n<\/ul>\n<p>Note that these percentages can only be used in the <code>border-image<\/code> property.  The <code>border-width<\/code> property must continue to use the pixel values:<\/p>\n<div id=\"percentageExample\">\nThis is the CSS used to generate this:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n   \/*\r\n    * These border widths must match the border-image numbers\r\n    *\/\r\n    border-width: 23px 22px 22px 26px;\r\n \tborder-color: black;\r\n   \/*\r\n    * Note that all browsers use their respective vendor prefix.\r\n    *\/\r\n   -moz-border-image:    url('chain.png') 28% 27% 27% 32% round;\r\n   -webkit-border-image: url('chain.png') 28% 27% 27% 32% round;\r\n   -o-border-image:      url('chain.png') 28% 27% 27% 32% round; \r\n   border-image:         url('chain.png') 28% 27% 27% 32% round;\r\n<\/pre>\n<\/blockquote>\n<\/div>\n<p>Now, why on earth would you want to use percentages, since pixels are probably more accurate?  I don&#8217;t see there being any need for bitmap images, but <strong>Webkit browsers (i.e. Safari and Chrome) can use SVG vector images as a <code>border-image<\/code> as well<\/strong>.  Since SVG images are resolution independent, I would assume it is more accurate to use percentages.  It would be worth looking into percentage widths more when SVG border-image support reaches critical mass, since the other browser manufacturers may handle SVG support differently than Webkit.<\/p>\n<h2>Degrading Gracefully and Progressive Enhancement<\/h2>\n<p>It is important that developers ensure their designs degrade gracefully so that pages not only <strong>look decent in browsers that don&#8217;t support <code>border-image<\/code><\/strong>, but also look nice when a compliant browser is loading the images, especially <strong>when loading a high-bandwidth page or a page on a slow connection<\/strong>.  Not only should you ensure the <code>border-color<\/code> and <code>border-style<\/code> are set, but it is a good idea to ensure that the look of the fallback border is as close as possible to border-image as possible.  Let&#8217;s take a look at the &#8220;framed border&#8221; we used at the top of this page:<\/p>\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>Firefox<\/th>\n<th>IE9<\/th>\n<\/thead>\n<tbody>\n<td><div id=\"attachment_2634\" style=\"width: 365px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxFallback.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2634\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxFallback.png\" alt=\"Screenshot of how the border-image example at the top of the page looks in Firefox.\" title=\"Screenshot of how the border-image example at the top of the page looks in Firefox.\" width=\"355\" height=\"284\" class=\"size-full wp-image-2634\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxFallback.png 355w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxFallback-300x240.png 300w\" sizes=\"auto, (max-width: 355px) 100vw, 355px\" \/><\/a><p id=\"caption-attachment-2634\" class=\"wp-caption-text\">Screenshot of how the border-image example at the top of the page looks in Firefox.<\/p><\/div><\/td>\n<td><div id=\"attachment_2633\" style=\"width: 372px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/IEfallback.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2633\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/IEfallback.png\" alt=\"Screenshot of how the border-image example &#039;falls back&#039; in IE9.\" title=\"Screenshot of how the border-image example &#039;falls back&#039; in IE9.\" width=\"362\" height=\"291\" class=\"size-full wp-image-2633\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/IEfallback.png 362w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/IEfallback-300x241.png 300w\" sizes=\"auto, (max-width: 362px) 100vw, 362px\" \/><\/a><p id=\"caption-attachment-2633\" class=\"wp-caption-text\">Screenshot of how the border-image example 'falls back' in IE9 using the ridge border-style.<\/p><\/div><\/td>\n<\/tbody>\n<\/table>\n<p>You can also be fancy and use <a href=\"http:\/\/www.modernizr.com\">modernizr<\/a> to do some extra progressive enhancement styling by using the <br \/><code>html.no-borderimage<\/code> selector.  I have done this using the comments section of my blog posts.<\/p>\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>Firefox<\/th>\n<th>IE9<\/th>\n<\/thead>\n<tbody>\n<td><div id=\"attachment_2639\" style=\"width: 310px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxBalloon.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2639\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxBalloon-300x106.png\" alt=\"Screen shot of comment on my blog using the balloon border-image in firefox.\" title=\"Screen shot of comment on my blog using the balloon border-image in firefox (Click to see full screenshot).\" width=\"300\" height=\"106\" class=\"size-medium wp-image-2639\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxBalloon-300x106.png 300w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/firefoxBalloon.png 579w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2639\" class=\"wp-caption-text\">Screen shot of comment on my blog using the balloon border-image in firefox (Click to see full screenshot).<\/p><\/div><\/td>\n<td><div id=\"attachment_2638\" style=\"width: 310px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/ieBalloonFallback.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-2638\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/ieBalloonFallback-300x66.png\" alt=\"Screen shot of the same comment using modernizr to style the comment differently on browsers that don&#039;t support border-image (Click to see full screenshot).\" title=\"Screen shot of the same comment using modernizr to style the comment differently on browsers that don&#039;t support border-image (Click to see full screenshot).\" width=\"300\" height=\"66\" class=\"size-medium wp-image-2638\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/ieBalloonFallback-300x66.png 300w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/03\/ieBalloonFallback.png 591w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-2638\" class=\"wp-caption-text\">Screen shot of the same comment using modernizr to style the comment differently on browsers that don't support border-image (Click to see full screenshot).<\/p><\/div><\/td>\n<\/tbody>\n<\/table>\n<h2>Using With Background Images<\/h2>\n<p>If you are using a <code>border-image<\/code> without a transparent colour or alpha channel, the center of your <code>border-image<\/code> will hide any <code>background-image<\/code> the object may have.  If you want to have a separate <code>background-image<\/code>, you must &#8220;cut-out&#8221; the middle of the <code>border-image<\/code> using your graphics editor with a transparent colour.  For instance, the example at the top of the page with the picture frame <code>border-image<\/code> has a photo of clouds as a <code>background-image<\/code>.   This allows developers to create more graphically rich block-level elements.<\/p>\n<h2>Hey! What about IE?<\/h2>\n<p>Unfortunately, IE doesn&#8217;t support <code>border-image<\/code> natively.  <strong>I <em>may<\/em> have a workaround for this using cssSandpaper<\/strong>, but it needs a lot more testing to see if it is a truly viable polyfill for this effect.  If I am successful,  I will post whether that solution as an addendum to this blog post.<\/p>\n<h2>Conclusion<\/h2>\n<p><code>border-image<\/code> can be used today to make some very interesting effects that can be degraded gracefully in browsers that don&#8217;t support it.  It can speed up design time considerably since you don&#8217;t have to use your graphics editor to cut up images.  And I&#8217;m sure it will waste a lot of your time while you play and see how it can be used effectively.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2011\/03\/front.png\" \/> Using the CSS3 <code>border-image<\/code> property, you can make coo graphical borders without cutting up images to bits. There are a few gotchas that developers should be aware of before implementing it and this article will cover these caveats, a tool that you can use to help generate border-images effectively, and a few strategies to ensure it gracefully degrades in older browsers<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[98,38,1],"tags":[],"class_list":["post-2536","post","type-post","status-publish","format-standard","hentry","category-border-image","category-css3","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/2536","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=2536"}],"version-history":[{"count":171,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/2536\/revisions"}],"predecessor-version":[{"id":2717,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/2536\/revisions\/2717"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=2536"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=2536"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=2536"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}