1

I know I can solve the problem below using <img /> and PHP (or javascript for that matter), but I'd like to solve it using just CSS, if I can.

I have marked up a language menu, in which I would like a flag icon to appear beside each named language.

Ideally, I would like to not have to add a new line to the CSS, every time I add a new language.

But is there any way - using attr() or CSS Custom Properties or some other method - that I can have the browser derive the correct background-image for each list item, using just (e.g.) class="fr" and data-language="fr"?

N.B. I am quite prepared for this to be beyond the current capabilities of CSS - but I am curious to find out if there is any inventive way of approaching this.

.language li {line-height: 40px;}
.language li::before {content:''; display:inline-block; position:relative; width:27px; height:27px; margin-right:9px; vertical-align:middle; background-color: rgb(191,191,191); border-radius:3px;}
.language li.de::before {background-image: url('/flags/de.png');}
.language li.en::before {background-image: url('/flags/en.png');}
.language li.es::before {background-image: url('/flags/es.png');}
.language li.fr::before {background-image: url('/flags/fr.png');}
<div class="language">
<h2>Select Language:</h2>
<ul>
<li class="en" data-language="en">English</li>
<li class="de" data-language="de">Deutsch</li>
<li class="es" data-language="es">Español</li>
<li class="fr" data-language="fr">Français</li>
</ul>
</div>

Additional Information:

My first approach was inadequate because it did not allow the flag icons to have rounded corners:

    .language li {
    background-position:0 center;
    background-size: 27px 27px;
    background-repeat: no-repeat;
    padding-left:36px;
    }
    
    .language li.de {background-image: url('/flags/de.png');}
    .language li.en {background-image: url('/flags/en.png');}
    .language li.es {background-image: url('/flags/es.png');}
    .language li.fr {background-image: url('/flags/fr.png');}
<div class="language">
<h2>Select Language:</h2>
<ul>
<li class="en" data-language="en">English</li>
<li class="de" data-language="de">Deutsch</li>
<li class="es" data-language="es">Español</li>
<li class="fr" data-language="fr">Français</li>
</ul>
</div>

But I am happy to skip the rounded corners if there is any potential here for achieving what I am aiming for.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Rounin
  • 27,134
  • 9
  • 83
  • 108
  • I thought I should add the `php` tag because the question is most easily solved by using `php` and `img`. Is it wrong to include this tag? If you can explain why it's wrong, I will remove the `php` tag. Thank you, @Epodax. – Rounin Jul 25 '16 at 12:18
  • You can probably fiddle around with `attr()` but doing it with JS will be simpler and more semantic. – Gofilord Jul 25 '16 at 12:19
  • 1
    I believe in sass, postcss or cssnext you could achieve this using variables, but I'm guessing you're looking for just a vanilla CSS approach. – Toby Jul 25 '16 at 12:29
  • 1
    No, this is not possible with basic CSS....you would need a preprocessor but that would just output the same CSS anyway, It would make easier to *write* but not any less verbose. – Paulie_D Jul 25 '16 at 12:30
  • Possible duplicate of [CSS set background-image by data-image attr](http://stackoverflow.com/questions/26967890/css-set-background-image-by-data-image-attr) – Vucko Jul 25 '16 at 13:24

2 Answers2

1

Currently, it is not possible without Javascript or any other programming language. Hopefully in the future we will be able to by using the attr() function, to get the attribute value from the element.

When using a pseudo-element, it gets the attribute from the original element. So you can do background-image: attr('data-bg' 'url') to get the data-bg attribute and treat it as a URL.

Vucko
  • 20,555
  • 10
  • 56
  • 107
Jerad Rutnam
  • 1,536
  • 1
  • 14
  • 29
  • Thanks for that pointer, @Jerad! I see (from https://developer.mozilla.org/en-US/docs/Web/CSS/attr) that `background-color:attr(data-language url, '/flags/eu/');` is definitely the (future) native CSS syntax for the kind of thing I am looking for. – Rounin Jul 25 '16 at 13:28
  • 1
    You are most welcome, and keeping finger crossed. Hope it will available soon. :) – Jerad Rutnam Jul 25 '16 at 13:38
  • Yes. And wow. It's the worst supported CSS feature I've ever seen. See: http://caniuse.com/#feat=css3-attr . – Rounin Jul 25 '16 at 13:39
0

For now, I have gone with:

CSS:

.language li img {
position:relative;
display:inline-block;
width:27px;
height:27px;
margin-right:9px;
vertical-align:middle;
border-radius:3px;
}

PHP:

<?php

for ($i = 0; $i < count($Language_Key); $i++) {

echo '
<li class="'.$Language_Key[$i].'">
<a href="/'.$Language_Page[$i].'/">
<img data-language="'.$Language_Key[$i].'" src="/flags/'.$Language_Key[$i].'.png" title="'.$Language_Name[$i].'" alt="Language Flag ('.$Language_Name[$i].')" />'.$Language_Name[$i].'
</a>
</li>
';

}

?>

but I'm still keen to hear of any innovative non-preprocessor approach, should there be a clever way to tackle this in native CSS.

(I'll concede that at the end of the day, none of this matters stupendously - it's all just an ongoing quest for elegantly marked-up documents).

Rounin
  • 27,134
  • 9
  • 83
  • 108