359

Suppose I want to decorate links to certain file types using an image. I could declare my links as

<a href='foo.pdf' class='pdflink'>A File!</a>

then have CSS like

.pdflink:after { content: url('/images/pdf.png') }

Now, this works great, except if pdf.png isn't the right size for my link text.

I'd like to be able to tell the browser to scale the :after image, but I can't for the life of me find the right syntax. Or is this like background images, where resizing just isn't possible?

ETA: I'm leaning towards either a) resizing the source image to be the "right" size, server-side and/or b) changing the markup to simply supply an IMG tag inline. I was trying to avoid both those things but they sound like they'll be more compatible than trying to do stuff purely with CSS. The answer to my original question seems to be "you can sort of do it, sometimes".

Coderer
  • 25,844
  • 28
  • 99
  • 154
  • 1
    Is there a compelling reason that you're not using 'img' tags with 'a' tags wrapped around them? That's the more typical syntax for an image that is also a link. I say this because even if you get your method to work, you may be confusing other developers. CSS also has a strong reputation for inconstancy between browsers/versions. – Servy Jan 23 '12 at 20:31
  • 5
    I appreciate the issue, it's just that I don't necessarily control the markup generation -- in this case I can only re-style, not re-structure. – Coderer Jan 23 '12 at 21:06
  • Lengthy discussion on the W3C mailing list: http://lists.w3.org/Archives/Public/www-style/2011Nov/thread.html#msg451 – user123444555621 Jan 24 '12 at 18:34

16 Answers16

507

Adjusting the background-size is permitted. You still need to specify width and height of the block, however.

.pdflink:after {
    background-image: url('/images/pdf.png');
    background-size: 10px 20px;
    display: inline-block;
    width: 10px; 
    height: 20px;
    content:"";
}

See the full Compatibility Table at the MDN.

Ansel Santosa
  • 8,224
  • 1
  • 28
  • 39
  • 3
    This is great except that most of our clients are on IE 7 or 8 (corporate nonsense, sorry). – Coderer Jan 23 '12 at 21:06
  • 18
    If that's the case, you shouldn't be using `:after` at all. [It's not supported below IE8.](https://developer.mozilla.org/en/CSS/:after#Browser_compatibility) – Ansel Santosa Jan 23 '12 at 21:08
  • 27
    This technique also required setting `width: 10px; height: 20px;` to see the image. – here Apr 19 '14 at 21:50
  • 6
    To note also that this indeed works, but **only** with the specific `background-image` property, the simple `background` will not work. – Gruber Jun 12 '14 at 14:29
  • 6
    (For `:before`) I also needed `position: absolute`, and `left: -10px`. – Hugo Aug 14 '15 at 07:59
  • 2
    Edited to add `display: inline-block` which fixed it for Chrome, pseudo-elements are `display: inline` by default so `height` and `width` are not applied, making the element only as big as its text content (which is empty) – Ansel Santosa Feb 13 '16 at 17:06
  • Is there any advantage in using background-image + background-size instead of just using content with a specified height/width? The latter works for me just fine, also the original question show a code using content, not background. – gdvalderrama May 11 '16 at 15:04
  • 2
    I think changing to ( background-size: 100% 100%; ) will improve the code, so you only have to change your "width" and "height" styles to set the image size. – santillanix Nov 22 '16 at 11:30
  • Probably want to add background-repeat: no-repeat; – Kimball Oct 12 '17 at 20:45
  • I'm using wkhtmltopdf to convert an HTML document into PDF. I've wanted to highlight the first `span` of a code-block as the file location and append a file PNG to the text content. This worked like a charm! – bezbos. May 21 '23 at 18:19
134

Note that the :after pseudo-element is a box, which in turn contains the generated image. There is no way to style the image, but you can style the box.

The following is just an idea, and the solution above is more practical.

.pdflink:after {
    content: url('/images/pdf.png');
    transform: scale(.5);
}

http://jsfiddle.net/Nwupm/

Drawbacks: you need to know the intrinsic dimensions of the image, and it leaves you with some whitespace, which I can't get rid of ATM.

Community
  • 1
  • 1
user123444555621
  • 148,182
  • 27
  • 114
  • 126
  • 10
    zoom: 0.5 is also worth considering. – Alex Jun 11 '13 at 12:03
  • I like the idea of this solution, but it throws the positioning off, esp in an inline-block scenario. (IE 11) – Christopher Davies Aug 05 '14 at 02:22
  • 1
    zoom is not well supported. –  Oct 02 '15 at 14:37
  • 1
    the jsfiddle is not changing the size. I'm using the latest Firefox. I also tried the last jsfiddle example in this post using zoom, and it does not work, either. – Ryan Feb 19 '16 at 16:41
  • Works perfect on chrome – Rahul Feb 27 '17 at 07:47
  • Worked where zoom, width and height all failed – Little Bobby Tables Apr 04 '17 at 10:52
  • Not sure why having to know the intrinsic dimension of the image is a drawback. i would say 99.999999% of the time this will be the case – JSON May 01 '18 at 15:22
  • 1
    Just a note: in my case, I had to put `position: absolute` in order to get `transform: scale(0.5)` to actually work. I also had to put `position: relative` in the "parent" element (the owner of the `:after` pseudo) for sanity. Also, I had to add `translate(-16px, -16px)` to my transform to position the 16x16 icon correctly. The `position: absolute` also has the benefit of eliminating the whitespace problem. – Braden Best Aug 04 '18 at 07:11
39

Since my other answer was obviously not well understood, here's a second attempt:

There's two approaches to answer the question.

Practical (just show me the goddamn picture!)

Forget about the :after pseudo-selector, and go for something like

.pdflink {
    min-height: 20px;
    padding-right: 10px;
    background-position: right bottom;
    background-size: 10px 20px;
    background-repeat: no-repeat;
}

Theoretical

The question is: Can you style generated content? The answer is: No, you can't. There's been a lengthy discussion on the W3C mailing list on this issue, but no solution so far.

Generated content is rendered into a generated box, and you can style that box, but not the content as such. Different browsers show very different behaviour

#foo         {content: url("bar.jpg"); width: 42px; height:42px;}  
#foo::before {content: url("bar.jpg"); width: 42px; height:42px;}

Chrome resizes the first one, but uses the intrinsic dimensions of the image for the second

firefox and ie don't support the first, and use intrinsic dimensions for the second

opera uses intrinsic dimensions for both cases

(from http://lists.w3.org/Archives/Public/www-style/2011Nov/0451.html )

Similarly, browsers show very different results on things like http://jsfiddle.net/Nwupm/1/ , where more than one element is generated. Keep in mind that CSS3 is still in early development stage, and this issue has yet to be solved.

user123444555621
  • 148,182
  • 27
  • 114
  • 126
  • 1
    @TJ Each separate answer deserves an answer (If that's not obvious enough), which will get different amounts of upvotes and will be seen/quoted/shared differently based on the contents of the answer. – Timo Huovinen Jul 19 '18 at 06:23
23

You should use background instead of image.

.pdflink:after {
  content: "";
  background-image:url(your-image-url.png);
  background-size: 100% 100%;
  display: inline-block;

  /*size of your image*/
  height: 25px;
  width:25px;

  /*if you want to change the position you can use margins or:*/
  position:relative;
  top:5px;

}
santillanix
  • 1,947
  • 18
  • 17
10

diplay: block; have no any effect

positionin also works very strange accodringly to frontend foundamentals, so be careful

body:before{ 
    content:url(https://i.imgur.com/LJvMTyw.png);
    transform: scale(.3);
    position: fixed;
    left: 50%;
    top: -6%;
    background: white;
}
10

Yes, the original question was asked eight years ago, but it's actually relevant today as its always been. Now, I've been going from pillar to post over this issue of ::before, for about a week ::after, and its been driving me round the bend.

From this page, and others on the subject - I've finally put it together and sized an image down in the pseudo tag.

** Running note .colnav is just my container class, that holds an < UL > and < LI > set of tags with a set of < a hrefs inside.

Below is the code (complete)

.colnav li.nexus-button a:hover:before {   
    background-image: url('/images/fleur-de-lis.png');
    background-size: 90px 20px;
    background-repeat: no-repeat;
    width: 130px;
    height: 20px;
    margin-left: -120px;
    margin-top: -3px;
    transform: scale(1.5);
    content: "";
    position: absolute;
}

The image file was (is) 120 x 80, and the picture got reduced right down to 90x 20, where it then fitted quite nicely behind the html href tag, and it all came together with that position: absolute statement at the end.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Terry McBride
  • 101
  • 1
  • 4
4

Here is another (working) solution : just resize your images to the size you want :)

.pdflink:after {
    display: block;
    width: 20px;
    height: 10px;
    content:url('/images/pdf.png');
}

you need pdf.png to be 20px * 10px for this to work. The 20px/10px in the css are here to give the size of the block so that the elements that come after the block are not all messed up with the image

Don't forget to keep a copy of the raw image in its original size

Thomas
  • 8,306
  • 8
  • 53
  • 92
4

Nowadays with flexbox you can greatly simplify your code and only adjust 1 parameter as needed:

.pdflink:after {
    content: url('/images/pdf.png');
    display: inline-flex;
    width: 10px;
}

Now you can just adjust the width of the element and the height will automatically adjust, increase/decrease the width until the height of the element is at the number you need.

rhysclay
  • 1,645
  • 3
  • 22
  • 42
3
.pdflink:after {
    background-image: url('/images/pdf.png');
    background-size: 10px 20px;
    width: 10px; 
    height: 20px;
    padding-left: 10px;// equal to width of image.
    margin-left:5px;// to add some space for better look
    content:"";
}
Ravi Soni
  • 953
  • 1
  • 7
  • 17
3

You can use the zoom property. Check this jsfiddle

Plamen
  • 330
  • 2
  • 8
  • 1
    Checking the jsfiddle, both are the same size and zoom is highlighted in red. – Ryan Feb 19 '16 at 16:34
  • It does not resize in Firefox 53 at the moment. Hopefully, this can be implemented in a later version of Firefox. It's good to know that it works in Chrome at least. :-) – Ryan May 03 '17 at 15:03
3

Instead of setting the width and height of the background image, you can set width and the height of the element itself.

.pdflink::after {
  content: '';
  background-image: url(/images/pdf.png);
  width: 100px;
  height: 100px;
  background-size: contain;
}
Usman Ahmed
  • 2,392
  • 1
  • 20
  • 17
1

I used this font size control width

.home_footer1::after {
color: transparent;
background-image: url('images/icon-mail.png');      
background-size: 100%;      
content: ".......................................";
font-size: 30pt;
}
1

You can change the height or width of the Before or After element like this:

.element:after {
  display: block;
  content: url('your-image.png');
  height: 50px; //add any value you need for height or width
  width: 50px;
}
Nesha Zoric
  • 6,218
  • 42
  • 34
0
content: "";
background-image: url("yourimage.jpg");
background-size: 30px, 30px;
uyghurbeg
  • 176
  • 3
  • 8
0

Stumbled upon this myself and discovered the following: if you are replacing content with url('/path/to/svg'), you can actually set the size of the image using width. The only caveat is that you must use dimensions relative to the root context, e.g. vh, vw, rem, etc.

#replaced {
content: url('https://www.svgrepo.com/download/507146/alert-triangle.svg');
width: 5.3125rem;
}
<ul>
<li>List item 1</li>
<li id="replaced">List item 2</li>
<li>List item 3</li>
</ul>

You can play with the above snippet and change width to see how it affects the size of the replaced item. 1rem is (usually) 16px (the default font size for the <html> element), so the math is your_desired_width divided by 16 equals width in rem. At least it works in Firefox and Chrome consistently, did not check Safari, though.

galaxy
  • 424
  • 2
  • 7
  • Actually, it works with normal dimensions too. The issue is that in some cases padding affects the viewbox and the embedded image starts to scale down. – galaxy Feb 27 '23 at 12:05
0

You can use css scale property for transform the object and if you use position:absolute, then you can use transform-origin property

.head-inner .confeti:after {content: url(img/flag2.png); position: absolute; right: 0; top: 0; transform: scale(.6); transform-origin: right top;}