Border Imaging

Published 7 years, 1 month ago

As I dig into the nooks and crannies of the various CSS3 modules, I’ve come across something that seems like I should be able to do, but I can’t make it work in browsers.  Now, I know as well as anyone that if you try to do something and browsers won’t do it, it might well be the fault of the browsers.  Particularly if you can get various browsers to fail differently on the same declaration, as I have.  But this is, bizarrely, complicated enough that it’s hard to be sure if it’s me or them.

So allow me to pose this to you as a challenge.  Given the following ideal rendering, how would you arrive at the depicted result using the single 5-pixel-by-5-pixel image shown within the content?

Note that it doesn’t have to be quite as clean as this—if there are partial diamonds adjacent to the corners where repeated images get clipped, that’s fine.

Should you answer, please be clear which type of answer you’re giving:

  1. What the specification says you should write to make this happen.  Note to those tackling this fresh: I think the descriptive prose for border-image-slice (yes, -slice) makes this harder than it seems, but I could be wrong.
  2. What you wrote to get browsers to do it consistently.  (Safari, Firefox, and Opera at a minimum.  Did IE9 get border images yet?  Vendor prefixes not required unless you had to write different values for different browsers.)
  3. Both spec- and browser-friendly, which is of course what we really want.

I’m really curious to see if anyone cracks this one, because that person I will grill mercilessly until either I understand what’s happening or one of us starts plotting to have the other killed.

  • Published
  • Categorized under CSS
  • 39 responses so far

  1. Hi Eric,

    As part of my site’s redesign I’ve elected to use the swanky new CSS property for border-images. Much to my initial dismay, there is no support for this in IE9 yet. IE visitors to my site will receive a different experience to those using Webkit/Gecko.

    One thing I found (in my implementation) was that I had to declare the border-width separately, in addition to the short-hand notation in the border-image declaration:


    border-image: url(main_imgBorder.png) 18 19 46 32 repeat;

    For the ‘slice’ that gets repeated along the top x-axis, this section of the image being used had to be 4px minimum in width for this to display correctly.

    In short, I think your original image needs to become a 15×15 image, with 9 repetitions of the original red dot (3 rows x 3 columns).

    I have encountered additional oddities in my implementation, which I will be writing up – once I’ve actually completed the site build!



  2. As the implementations of border-radius use guides to slice up an image, I’m not sure if using just one, single 5x5px star image will work at all (it certainly didn’t for me). I have to admit that the border-image concept and terminology are confusing as they do suggest using a single image in a border space and not this slicing malarkey.

    Making a larger image with repeating areas was my only option. (See the image)

    This CSS works in Webkit and Firefox 4:

    .ihatetimvandamme {
    -moz-border-image : url(ihatetimvandamme.png) 5 round;
    -webkit-border-image : url(ihatetimvandamme.png) 5 round;
    border-image : url(ihatetimvandamme.png) 5 round;
    border-width : 5px; }

    Opera is a no-go no matter what I do, and I have no Windows running here so I can’t test IE9. Try changing the border-width property too. That’s fun.

    My five-minute result. I’m sure cleverer people know better?

  3. Having thought about this I’ve come to the conclusion that it isn’t so much that the syntax is at fault, but that the name of the property is misleading. What border-image does is slice an element up into four sides and four corners, and overlay those on the border of the element; really it’s framing the element,so perhaps changing the property name to border-frame would be more logical.

    If this were done, the border-image property could be changed to use a more simple syntax, which repeats an image around the element border (I’m sure that’s not as simple as I’ve made it sound). If this causes problems with backwards compatibility, perhaps another new property would have to be created (border-decoration?)

  4. Okay, so dominic and Andy both came to the same conclusion I did. I’m really hoping someone will pop in here to show us how we’re wrong, because otherwise this seems like a massively huge oversight in terms of simply supporting a simple and likely very common use of border images.

  5. I’m coming to the same conclusion as Mr Clarke as I had to create the same image.

    Although, I was able to get it to work in Firefox 3.6.13 and Opera 11. Of course it requires the vendor prefix.

    -o-border-image: url(‘diamond2.png’) 5 round round;

    IE9: no dice.

  6. As Andy said, the image he provided is the correct means of using border-radius.

    You simply have to imagine a 3×3 grid across the image, where the central vertical column and central horizontal row are what is repeated. Imagine your image being stretched out without corners being stretched or widths altered.

    The reason it is based on grid guides and not simply repeating the image I imagine is because designers usually want full control of the corners of the styled element.

    Whilst your scenario means that this adds complexity, having an option to enable the functionality you describe would require an additional flag on one of the functionalities assuming you don’t want to drop the current way it works.

  7. Peter, I agree with everything you said. This really is a shorthand way of creating a frame. The property name (actually all the related names) create a huge amount of confusion because they trigger expectations the actual behavior of the properties don’t meet.

    My guess is that it’s too late to change it, of course. I’ve been pointing out for years that background-origin is badly misnamed (and also blocking a feature which would suit the name far better) but my arguments have yet to impress the WG.

  8. It looks like you do have to create an image that has repeating images for each side of the border. I see how having a single image repeat around the border would make logical sense for the border-image property, but it wouldn’t be as flexible. has a good example that shows different corner and side images.

  9. That is a confusing part of the spec. With what the others said and Peter as well, it doesn’t sound like it should be chopping the image up into a grid. I see the usefulness of that, you only need one image. But if you just want to do a simple red-dotted border like Eric was showing, it’s way too complex for what is trying to be accomplished.

    At least at first glance it is, with the spec that big. Andy’s code is actually quite concise. Knowing you need to border-width looks key as well.

  10. Damn, went to lunch with the post ready to submit, and got scooped by everyone.

    The only thing you need to do is create a 15×15 image with 8 diamonds, then use “border-image: url(diamonds) 5 repeat;” (with the appropriate prefixes, currently).

    I don’t think complicating the border-image syntax with additional functionality to spam a single image to all 8 border regions is worthwhile, when you can so easily just turn that turn it into an 8-part image when you need this functionality.

  11. Saw your post and whipped up something here, with varying degrees of success.

    I’m using the 5px by 5px image you specified, and it seems to work differently across different browsers.

    It renders almost correctly in Safari which seems to scale the repeating image down if the border size isn’t set at the end. With that set, it does render correctly.

    The border doesn’t render at all in Chrome unless the width is specified; once that’s set, it seems to render correctly.

    Firefox (3.6.1) doesn’t seem to play nicely, only displaying the diamonds in the corners, which is strange because Resig’s example seem to work. I suspect this is where the larger grid of diamonds would have to be used.

    I haven’t tried it in Opera or the others, but seems to be using the vendor-specific prefixes when showing off the demo for border-image, so it would be interesting to hear from someone how the others are rendering those demos.

  12. Yes, I have found the same. When I teach, I liken it to 9-slice scaling in some graphics programs. It still makes my head spin. There’s a good article that has a little widget in it that allows you to change settings and watch the image change, but their domain apparently expired. :(

    On a site I’m working on currently, I found that even if I want the border only on one side, I had to actually make a 3×3 grid of circles (with the middle blank). Of course, that might just be my own ignorance that made me believe that. But it worked this way.

    Code looks like this:
    border-width: 0 0 18px 0;
    -moz-border-image: url(../img/border-image.gif) 18 repeat;
    -webkit-border-image: url(../img/border-image.gif) 18 repeat;
    border-image: url(../img/border-image.gif) 18 repeat;

    I really believe this is terribly named and confusing and like the border-frame idea.

  13. I wrote a blog post just now explaining the property:

  14. What’s even stranger is that if you use that 5×5 image in your example, and use following CSS:

    .example {
    border-width: 5px;
    -webkit-border-image: url(ihateandyclarke.png) 5 repeat;
    -moz-border-image: url(ihateandyclarke.png) 5 repeat;
    border-image: url(ihateandyclarke.png) 5 repeat;

    … it works fine in WebKit (that is, it gets your desired result), but Firefox just puts the image in all 4 corners, with no repeating border. Nothing seems to fix it in Firefox.

    IE9 does not yet support border-image, so it’s a non-issue there.

    You’re absolutely right, though — there should be a way to just use a simple image that repeats, without having to worry about the 9 slices.

    Here’s an idea: Why don’t they add an extra property like border-image-type with two possible values: “standard” (which means the 9-slice method is used) and “simple” (which means the image is repeated naturally without the need for the 9 slices — as long as the border-width is set correctly to match the image’s width/height).

    I don’t think it would be too difficult to add this to what’s already in the spec, and to what’s already supported by the user agents.

  15. Tab, you don’t think that it’s worth supporting a case like the one I describe? You don’t think authors will be interested in repeating a single image all the way around an element without having to do Fireworks-style image slicing? Because I certainly do. Especially if the image is (optionally) rotated for each side. It would make alternate dash patterns very easy to accomplish, for example, along with many other things. The way it’s done now, drawing a frame, requires pixel counting and construction work.

    At the very least, changing the property names to use the word ‘frame’ would help prevent the confusion many of us seem to be experiencing. Whether that would make it border-frame-* or border-image-frame-* doesn’t much matter to me personally, but others might have stronger opinions.

  16. It’s only the shorthand that works correctly in the “standards-compliant” browsers. IE9 is not even close. Not every browser is going to understand the entire border-image syntax. Or at least that was my understanding when I last read the border-image property.

    I’m just left wondering how misused this will become and why we need to have all these new special CSS3 trinkets and baubles if CSS2.1 isn’t even finished yet.

    I think we’re heading back to the days where tables ruled layouts and those tables had gawdy and hideous tye-dyed or animated gif borders.

  17. Think I got something.
    I’m using:

    section p {
    padding: 5px 10px;
    -webkit-border-image: url(border-image-question.png) 100 repeat;
    border-width: 5px;

    You can see the result in (webkit).

    What do you think?

  18. Awesome, Germán. Now: why does it work, and will it work in other browsers if you add the same declaration with their prefixes? I’d try it myself but your construction of the test makes it hard to copy locally.

  19. Eric, no, I don’t think that case is important enough to justify further complication to the syntax, when it’s *so easy* to just make an image that works witht he current syntax. You always have to balance functionality with ease-of-use. I think the current syntax is as far toward functionality as is practical, and is already dangerously confusing to use.

    Doing things like rotating the image for the sides makes the necessary complications to the syntax even more burdensome. Just make a larger image!

  20. Tab, I didn’t ask if it was worth complicating the syntax of border-iamge. I asked if it was worth supporting at all.

    I like your “just make a bigger image!” argument. That’s like “Why do you need advanced layout when it’s *so easy* to just use more floats?”. Not to mention the evidence in this comment thread that the property names as they exist now are confusing and cause people to assume that the case I described is easy to do, when it’s actually impossible.

    But as I intimated in a previous comment and you’re amply demonstrating here, the WG is not so much interested in changing things that are misleading or confusing to authors when they can instead pat authors on the head and tell them “there, there, just stop bringing your expectations to the table, do it our way, and you’ll be fine”.

  21. I personally second your idea, Eric: border-frame-* for image grid-slicing functionality and border-image-* for simple image repeating.

  22. But… it’s *not* easy to just use more floats. Floats suck and are really painful and horrible. When there’s something that authors really want to do, but it’s really difficult, then we need to address it directly.

    Not *everything* needs the simplest possible solution, though. Going too far down that path produces an explosion of carefully-tailored solutions, which is counterproductive as you try and find the one that solves your particular problem. If it’s easy to get what you want by tweaking your approach and using an existing solution, then that’s probably the best thing to do. Hell, even if you *can’t* get exactly what you want, but you can get pretty close using an existing solution, it’s still probably best to say “use the existing solution”.

    In this case, just turning your one image into an 8-region image is completely trivial. It took me all of 20 seconds to do (not counting GIMP’s startup time). And by doing so, it’s then trivial to use with the existing solution (well, trivial once you’ve grokked the solution in the first place).

    And you then get things like rotating the images for each side *for free*, because you just bake that rotation into your image. Less spec work, less implementation work, less properties doing almost-but-not-quite-identical things for authors to learn.

    Seriously, I don’t understand why you’re pretending it’s hard to make a 15×15 image.

    (I have no particular opinion on the name; I don’t find -frame any more intuitive than -image, personally. But if you do, I suggest you bring it up on the mailing list asap.)

  23. In an age where we are striving to move towards a more semantic web, I think we will all agree that the current declaration is not the most intuitive (as evidenced by the array of confusion here). That said, the red dots are not to my tastes, but then that is a somewhat subjective viewpoint :-)

  24. I ended up avoiding the border-image property and going with a single dot, multiple backgrounds, and a tiny bit of padding.

    url(./dot.png) 0 0 repeat-x,
    url(./dot.png) 0 0 repeat-y,
    url(./dot.png) 0 100% repeat-x,
    url(./dot.png) 100% 0 repeat-y;
    padding: .5em;

  25. Germán’s example will work with any value of 5 or higher for the offset (i.e. the “100” that he’s using is not necessary — just use Chrome’s developer tools to change it on the fly to “5” and it will not affect the output).

    But the same code (with -moz) still does not work in Firefox (in my testing), so I don’t think that’s a solution.

  26. * replace “the most intuitive” with “immediately obvious”

  27. You’re right Louis, that “100” is not necessary.
    I do think there must be a solution, but I guess it will be a hack.
    I’m trying to achieve the same thing in FF4 and Opera, no luck so far :(

  28. Eric,

    So far I have achieved to show the whole border in webkit but only two borders in Opera and FF (top & bottom or left & right).

    Maybe that’s a start and someone with more experience than me can finish the work.
    (there must be a way!)

    Here’s the code:

    section p {
    padding: 5px 10px;

    /* webkit: done */
    -webkit-border-image: url(border-image-question.png) 5 round;

    /* moz: ?? */
    -moz-border-image: url(border-image-question.png) 5 0 round;

    /* opera: ?? */
    -o-border-image: url(border-image-question.png) 5 0 round;

    border-image: url(border-image-question.png) 5 round;
    border-width: 5px;

    The code is here:

  29. Germán, that is quite interesting. The problem is, even if you were able to get it to work the same, it would be pointless unless the code was exactly the same for all browser.

    One of the rendering engines is doing something wrong here, and the spec doesn’t seem to indicate which one (although I haven’t examined it in enough detail to say for certain).

  30. Here’s an alternative, using generated content to create nested artificial block-level elements inside the original paragraph:

    Not quite what you were looking for, but it’s an amusing workaround. Works in FF, Chrome, Safari, and Opera; haven’t tried IE9.

  31. I think the real problem is that it was planned/implemented as a stretching background image. I remember trying it when it was implemented and being peeved with the fact that by default it would set the middle part of that image as the element’s background. You have to plan it carefully and draw pixels and calculate, because the algorithm is not the same and whatever might repeat – err, pardon me – stretch beautifully in WebKit, has many chances to be mismatched in Gecko. It reminds me of the so many image workarounds that were used along the time for shadows, rounded corners etc. I’ll admit that it encourages creativity. But whoever found this logical for a border has a very twisted mind. I don’t expect it to work with the same code in all browsers(and why should I, they are different pieces of software), but at least one way to make it work for each of them? Without pushing pixels around?

  32. Louis,

    I’m not sure about that, we are using different syntaxes already:

    -moz-border-radius-topright vs -webkit-border-top-right-radius

    That’s the advantage of vendor specific prefixes. We can achieve the same results using different syntaxes.

    Anyway, it was just an experiment ;)

  33. Well in that case, Tab, we should dump border-image and its related properties entirely because we can do just about everything it does with multiple backgrounds, as Anton demonstrated. And anything we can’t do could be addressed by adding just an extra property or two, not the six that border-image et al. require to do this very specific thing that can be accomplished by tweaking an existing solution. Right?

    Meantime, please don’t accuse me of pretending things I’m not, because it needlessly lowers the quality of the discussion. I’m not pretending it’s hard to create a 3×3 grid image. I’m saying that the property name makes it counterintuitive that you have to do that for this simple and likely common effect, and that even once you’ve gotten past that intuitive pothole it’s a bit annoying to have to do it for simple cases that could literally be handled with a single property. Which, if it were, would most appropriately called border-image. (Well, given CSS naming conventions. I’d personally find image-border more appropriate but it’d violate long-standing naming patterns.)

  34. Awesome demonstration! Border images are an excellent addition to CSS.

    For anyone trying to quickly achieve a dotted line around without having to worry about border madness, just use the “outline: ” property. I really think its a long-forgotten property, and slips right by internet explorer’s typical disasters.

  35. Germán, yes technically you’re correct, but when you have something like “5 0 round” for Mozilla and “5 round” for WebKit, that is not very future-proof. What will you put in the standard syntax (the one with no prefix, that’s supposed to be listed last)?

    Also, it should be noted here that “round”, AFAIK, is not supported by WebKit. WebKit treats “round” as “repeat”. “round” is supposed to prevent the repeated image from being clipped at the corners. In my testing, Firefox removes the clipping, but WebKit does not.

  36. Germán,

    Ah, pardon me. You’re referring to the difference in the longhand notation. In that case, you’re correct. I’m a little puzzled at why they’re doing that, but that’s another issue.

    But again that raises the question: What should we use for the standard syntax? Good point,though…

  37. When I tried using a 5×5 image, the corners would only show in FF 3.6.13 as well. Andy Clarke’s technique works well as was stated (Opera/IE9 – no). “Confused” is only one word I would describe how I am when dealing with border-image.

    Something so simple, yet so confusing. Why bother having border-image when it could be simplified and renamed?

  38. After some further thinking, I’ve posted about this on www-style. We’ll see if anything comes of it. Thanks to everyone who took a crack at this! Maybe I’ll start a series called “Complexquiz”.

  39. Pretty neat effect, although I don’t want to endure the cross browser headache until *cough* IE at least displays CSS 2.0 decently ;)

Leave a Comment

Management reserves the right to edit or remove any comment, especially when abusive or irrelevant to the topic at hand. HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <em> <i> <q cite=""> <s> <strong> <pre class=""> <kbd>

Comment Preview

If you're satisfied with what you've written, then go ahead...