3

We are looking to obtain exactly this type of border for almost all img tags inside the content area of a CMS (wordpress/joomla) site (that's why we are searching for a solution using only CSS, without accesing any parent tag):

CSS border-image negative offset

First step goes smoothly with the code form here: http://border-image.com/ (the link should show our border image used), but it creates a space between the image and the edge of the actual border.

CSS border-image normal

We first tried some CSS rules that could do the job, but:

  1. border-image-outset: it only extends to outside, not inside, helps for cases where background is solid color
  2. outline-offset: works only for the outline, doesn't affects the border-image
  3. Multiple Backgrounds: Is the nearest one, but the borders show BELOW the image, so it needs to have a padding applied. We are expecting it to be partially over the image as intended (indeed it is what we've implemented until now).

We have already found many similar questions and tried using the most applicable answers:

  1. ::after : it needs the image to have content="" which disappears it.
  2. jquery $(img).after: We can't position the border elements relatively to the correspondent image, as they are precisely inserted AFTER the image (the same with before). We would require to set this on the parent tag which most times doesn't has the same size of the img. We are at the moment trying some wrap.

Until now we haven't been able to solve the problem as intended.

Here's a JSfiddle where we are making tests with all above 5 options and have enough material to work (neat image, grouped and separated corners, all mentioned codes appliead, etc).

We would really appreciate somebody achieving the exact result applicable for the img tag.

DavidTaubmann
  • 3,223
  • 2
  • 34
  • 43

2 Answers2

2

::after is no good for img elements, because such pseudo elements are supposed to be inserted as a virtual child element inside the element, and image elements can not have children.

But why not simply wrap the image inside a span (can be done via jQuery), and then have the background applied to that?

.image-border {
    display:inline-block; /* so that it takes up the same space as the image */
    position:relative;
    padding:6px;
    background: url(http://i.imgur.com/0yCz3oA.png) top left,
      url(http://i.imgur.com/fWtyg99.png) top right,
      url(http://i.imgur.com/UcOam5I.png) bottom left,
      url(http://i.imgur.com/pjYWHyM.png) bottom right;
    background-repeat: no-repeat;
}
.image-border img {
    position:relative; /* for z-index to work */
    display:block; /* so that margins can work and there is no underline space reserved */
    margin:-3px; /* drag image “under” the borders on each side
                    by half of the border width resp. span padding */
    z-index:-1; /* make image display below the span */
}

http://jsfiddle.net/nfsuxbyL/

CBroe
  • 91,630
  • 14
  • 92
  • 150
  • This seems as an excellent solution for those who want to avoid the user to interact with the image! Great work! – DavidTaubmann Mar 13 '15 at 20:18
  • Oops, you’re right, that is a side-effect I hadn’t thought of … Yes, if you want the user to be able to interact with the image, then a solution that uses four separate border images works better. – CBroe Mar 13 '15 at 22:41
1

You need a wrapper to use $(img).after because border elements get size of the parent (and insert the corners to just that element). You can use this code and some css:

$('img').wrap('<div class="IMGwrapper"></div>')
$('.IMGwrapper img').eq(0).after('<img src="http://i.imgur.com/0yCz3oA.png" class="TL" />');
$('.IMGwrapper img').eq(0).after('<img src="http://i.imgur.com/pjYWHyM.png" class="BR" />');
$('.IMGwrapper img').eq(0).after('<img src="http://i.imgur.com/UcOam5I.png" class="BL" />');
$('.IMGwrapper img').eq(0).after('<img src="http://i.imgur.com/fWtyg99.png" class="TR" />');
.IMGwrapper {
  display: inline-block;
  position: relative;
  line-height: 0;
}
.IMGwrapper .TL,
.IMGwrapper .TR,
.IMGwrapper .BR,
.IMGwrapper .BL {
  position: absolute;
}
.IMGwrapper .TL {
  top: -3px;
  left: -3px;
}
.IMGwrapper .TR {
  top: -3px;
  right: -3px;
}
.IMGwrapper .BR {
  bottom: -3px;
  right: -3px;
}
.IMGwrapper .BL {
  bottom: -3px;
  left: -3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
jQuery'd Edges:
<img src="http://i.imgur.com/ZLmYjVc.png" />
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
gwer
  • 614
  • 3
  • 5
  • 1
    @davidtaubmann, this isn't a good solution. If you use it, you get 15 elements of border because $('img').after() is called for each previously inserted element. You can try this code to avoid excess elements: http://jsfiddle.net/0ubx770v/6/ – gwer Mar 12 '15 at 21:08
  • WOW! Excellent @gwer! We haven't implemented the first solution given (version 3 of the jsfiddle) but you're RIGHT! Thanks a lot for the self-repair... I've inspected the resulted code of the old version, and it's true, it has created 15 elements! We've edited your above solution, to avoid the creation of so much elements by those who could apply the old solution. – DavidTaubmann Mar 13 '15 at 20:38