CSS generated content and Google Chrome translate scores an own goal

While developing prototype designs for a French football magazine, I came across a strange bug when Chrome’s translate feature comes into contact with CSS generated content.

One of my current projects involves redesigning the website for French football magazine SO FOOT’s website. Being an “I can’t design without content” kind of guy, that means using examples of articles from their current website which, of course, are in French.

Part of my brief is to bring the design of the website closer to that of their printed magazine, with its eclectic mix of typefaces and styles. I love that Mandy Michael has been experimenting with Text Effects, so much so that I included a couple of her examples in Art Direction for the Web.

The final result working in Safari
The final result I’m developing; three typefaces layered within a single element.

Mandy’s techniques often involve a small amount of presentational HTML, but not so much I’ll get a red card. To achieve the effect, I add add a data- attribute to my text, in this case a headline:

<h1 class="type-family-jakob" data-heading="France-Norvège">France-Norvège</h1>

To create this three-dimensional effect using multiple fonts, I need the value of that attribute so I can position it before and after the headline:

[class*="type-family"] {
position: relative; }

[class*="type-family"]:after {
content: attr(data-heading);
position: absolute;
z-index: 1;
overflow: hidden;
left: 0;
top: 0;
font-size: inherit;
font-weight: normal; }

NB: You can also display content from attribute values, including alt, title, and in this case data-. Data attributes keep information hidden from everything including screen readers, but they remain accessible to CSS and addressable by scripts.

To complete the effect, I layer the headline and its two pseudo-elements. Each one uses a different font-family value:

.type-family-festivo {
font-family: 'FestivoLetters';
color: rgb(255,255,255); }

.type-family-festivo:before {
z-index: 1;
font-family: 'FestivoLettersPattern';
color: rgba(255,255,255,.5); }

.type-family-festivo:after {
z-index: 2;
font-family: 'FestivoLetters09';
color: rgb(255,255,255); }

The effect is exactly as I predicted using Safari, which is my day-to-day browser.

The final result working in Safari (again)
Safari screenshot of the final result; three typefaces layered within a single element.

So far, so good. Then, I checked my prototype in Google Chrome and let’s just say the result wasn’t what I had expected.

The final result not working in Google Chrome
Google Chrome screenshot; the page displays two languages, English and un peu de français.

After scratching my head for a while, I remembered that il était une fois, I’d told Google Chrome to always translate French into English.

The W3C states we should:

Always use a language attribute on the html tag to declare the default language of the text in the page. When the page contains content in another language, add a language attribute to an element surrounding that content.


As I’m designing a website for a french audience, I’d added lang="fr" to the html element in my templates:

<html lang="fr">

Google Chrome translates the content of a page, but not content that’s generated by CSS, so in my design I was seeing the translated copy from my headline’s <h1> element, but the original French from content generated from its data- attribute.

I hadn’t come across this problem before, but found several ways to prevent it. Google’s Help Centre suggests adding a proprietary meta element with a content value of notranslate:

<meta name="google" content="notranslate" />

This will stop Google Chrome from translating any content in a document, which seems to me like the HTML equivalent of drop-kicking a supporter. Luckily, Google offers a better solution in the form of the notranslate class attribute which will also prevent Chrome translating content. You could apply that class to the whole document too:

<html lang="fr" class="notranslate">

But, it’s best to limit what shouldn’t be translated to when we use CSS generated content with visible flow content:

<h1 class="type-family-jakob notranslate" data-heading="France-Norvège">France-Norvège</h1>
The final result now working in Google Chrome
Google Chrome screenshot of the final result; three typefaces layered within a single element and a win.

Google Chrome: 0
CSS Generated Content: 1

What a result!

Update: Eric Eggert let me know that using data- attributes as a source for CSS generated content means the content of my headline will be read by screen readers three times; once for the headline text, once for the :before and another for the :after pseudo-elements. Switching from data- to an area-label attribute prevents that from happening while still achieving the same visual result:

<h1 class="type-family-jakob notranslate" aria-label="France-Norvège">France-Norvège</h1>

[class*="type-family"] {
position: relative; }

[class*="type-family"]:after {
content: attr(aria-label);
position: absolute;
z-index: 1;
overflow: hidden;
left: 0;
top: 0;
font-size: inherit;
font-weight: normal; }


I’m available for hire to consult on and design products and websites. Based in North Wales, I travel regularly to work with clients world-wide.

Available from January 2020

Talk soon

For work enquiries email

Or call us on +44 (0)1745 851848


Stuff & Nonsense Ltd.
Eversleigh, Lon Capel,
Flintshire, North Wales,
LL18 6EJ, UK