root navigation content

Delavy for the Web

Bilingual thinking to improve the Web

Version FrançaiseEnglish Version

For proper display hreflang

samedi 13 juin 2009 [16:46:43]

Here is a CSS method to display the target language of a link (hreflang attribute) next to it. This target language is an essential information, especially when it is different of the text who contain it. We can display it with "CSS generated-content", with a combination of rules that we get a very supple method, who include a lot of scenario. You can find this style on userstyle.org.

Cet article existe aussi en version française.

  1. Parent language
  2. Link language
  3. Combined methods
  4. Optimisation
  5. The good cascade
  6. Control table

We want to display the target language of a link when it is different of the language from text who contain the link. But there are lot of scenarios depending to the attibutes... For those who are hurry, here is the good solution. For other, we are discovering how to reach it.

1° Language from ancestor of the link

In CSS, we use [lang="fr"] to select the parent language of an element. The rule say : "in a french content, the link who target anything other than french, it must put that next to, and the same thing for English". In CSS, that is translated to :

/* I display hreflang */
a[hreflang]:after{
	content: " ("attr(hreflang)")";
}

/* I remove it when it's the same language */
[lang="en"] a[hreflang="en"]:after,
[lang="fr"] a[hreflang="fr"]:after{
	content:none;
}

Notation :

  1. We can make more simple in using the not() selector [01], but it is not yet well implemented (in IE6-7-8 an Opera)[02].
  2. This is the only method who work on IE7
  3. I proceed by exclusion for my rule work for all hreflang. Otherwise, it would a declaration for each supposed language link. Here we just need a rule for each publishing language.

This method only work if the language is specified once. But a link can have several ancestor : a close relative in English (language of the article), and a distant relative in french (language of the website). In this cas, the result are uncertain. See exemple :

<body lang="fr">
  <p>[...] contenu français[...]</p>
  <div lang="en">
    <p>[...] English content [...]<br />
    Go to <a hreflang="en" href="#">google in English</a><br />
    Try <a hreflang="fr" href="#">google in french</a><br />
</body>

That give

[...] contenu français [...]

[...] English content [...]
Go to google in English
Try google in french

In this case, in the English text, the link who target on English[03] takes the attribute too, because it was the child of an English div. And changing the declaration order juste reverse the problem.

2° Language of the link

We can select the language of the link, that it inherit his most near ancestor, with :lang(en) (for English). This pseudo-class ignores the multiple ancestor and interpret the latter language attributed : a text is either in English, or in french. The rule say : "a link in french who don't target on french, it must have the hreflang attribute next to, the same for English". In CSS, that is translated to :

/* I display hreflang */
a[hreflang]:after{
  content: " ("attr(hreflang)")";
}

/* I remove it when it's the same language */
a[hreflang="en"]:lang(en):after,
a[hreflang="fr"]:lang(fr):after{
  content:none;
}

The matter is that sometimes, the link who target on french content itself is in french : so you take up the title of the article on wich you point to, for put it in the title of the link

<body lang="fr">
  <p>[...] contenu français[...]</p>
  <div lang="en">
    <p>[...] English content [...]<br />
    Go to <a hreflang="en" href="#">google in English</a><br />
    Try <a hreflang="fr" href="#">google in french</a><br />
    An article : <a hreflang="fr" lang="fr" href="#" >"J'aime Mozilla"</a></p>
  </body>

That give :

[...] contenu français[...]

[...] English content [...]
Go to google in English
Try google in french
An article : "J'aime Mozilla"

Here, for the third link (to the English article), the language of the body link is English. So the second rule applies (I remove it when it's the same language), to delete the attribute. We should identified the language of the most near ancestor, in order to write a fonctional rule.

3° Combined methods

So we take the second rule to solve problems with other declaration

We must create a rule to display the hreflang attribute when the links have the both lang and hreflang attributes, and when this hreflang is different from language of the container. We proceed in two stages :

  • We display hreflang for the all links who have the both hreflang and langattribute, regardless of the parent language.
  • We hide hreflang for links with the closest relative to the same as specified for the link.
/*When there are lang and hreflang, I display hreflang*/
a[lang][hreflang]:after{
content: " (" attr(hreflang) ")";
}

/*I delete it when it's the same language of the most near parent. */
:lang(en)>a[lang="en"]:after,
:lang(fr)>a[lang="fr"]:after{
content:none !important;
}

And this is ! :

<body lang="fr">
  <p>[...] contenu français[...]</p>
  <div lang="en">
    <p>[...] English content [...]<br />
    Go to <a hreflang="en" href="#">google in English</a><br />
    Try <a hreflang="fr" href="#">google in french</a><br />
    An article : <a hreflang="fr" lang="fr" href="#" >"J'aime Mozilla"</a></p>
  </body>

That give :

[...] contenu français[...]

[...] English content [...]
Go to google in English
Try google in french
An article : "J'aime Mozilla"

4° Optimisation.

Always with a view to create a general rule, we can add a few exclusions :

  • We delete hreflang when the attribute is empty. Because a[hreflang] make no differences between hreflang="" and hreflang="de".
  • We cancel the rule for titles : CSS generated content is not easy to handle, and in title that can make some troubles (and it's not very aesthetic).
/* I delete it when it was empty */
a[hreflang=""]:after{
  content:none !important;
}

/* I delete it when it was a title*/
h1 a[hreflang]:after,
h2 a[hreflang]:after{
  content:none !important;
}

5° The correct cascade

So the correct cascade, compacted, is :

/* 1 - I put attribute before link who have hreflang */
a[hreflang]:after{
  content: " ("attr(hreflang)")";
}

/* 2 - Je delete it when it's the same language */
a[hreflang="fr"]:lang(fr):after,
a[hreflang="en"]:lang(en):after{
  content:none;
}
 
/* 3 - when there are a language and a target language, I display hreflang*/
a[lang][hreflang]:after{
content: " (" attr(hreflang) ")";
}

 
/* 4 - I delete it when it's the in same language... */
:lang(en)>a[lang="en"]:after,
:lang(fr)>a[lang="fr"]:after,
/* 5 - .. when it's empty... */
a[hreflang=""]:after,  
/* 6 - ... and when it's a title.*/
h1>a[hreflang]:after, 
h2>a[hreflang]:after,
h3>a[hreflang]:after{
  content:none !important;
}

Here is a simplified version, with not() (not compatible IE or Opera). Because the language can be specified with an attribute Regional (e.g. "en-us"), I use CSS3 selector who allow to specify "who start by" : ^. So we write [lang^="en"] to guard against all eventualities.

/* I display hreflang when the target language is 
different than the language form the text */
a[hreflang]:not([hreflang="fr"]):lang(fr):after,
a[lang="fr"]:after,
a[hreflang]:not([hreflang="en"]):lang(en):after,
a[lang="en"]:after{
  content: " (" attr(hreflang) ")";
}

/* I delete it when there a just a lang and no hreflang,
or when it's  the same language */
:lang(en)>a[lang]:not([hreflang]):after,
:lang(fr)>a[lang]:not([hreflang]):after,
:lang(en)>a[lang="en"]:after,
:lang(fr)>a[lang="fr"]:after{
content:none;
}

/* I delete it when it's empty... */
a[hreflang=""]:after,
/* ... or when it's a title*/
h1>a[hreflang]:after,
h2>a[hreflang]:after,
h3>a[hreflang]:after{
  content:none !important;
}

6° Control Table

The table allows to check the functioning of the rule. If we use se simplified version, the last column with "de" is not correct : it would be added the option for lang(de) in the CSS.

Control of the rule (violet in th e unlikely event)
Language of the link hreflang en lang en hreflang en
lang en
hreflang es lang es hreflang es
lang es
hreflang fr
lang en
hreflang en
lang fr
hreflang fr
lang de
hreflang de
lang fr
unspecified
table in
English
Link Link Link link-es link-es link-es Link Lien link-de Lien
English Link Link Link link-es link-es link-es Link Lien link-de Lien
French Link Link Link link-es link-es link-es Link Lien link-de Lien
Spanish Link Link Link link-es link-es link-es Link Lien link-de Lien

Notes and references :

  • This rule is very practical in the style of Firefox (UserContent.CSS)
  • To precise language, a text is really better than a flag. A flag means country, not a language !
  • Here I use text, but Pompage.net works wonders with an image.

Texts, pictures, and design : Copyright © 2008 - 2009 Delaby Pierre.
Copyleft : This is a free work, you can copy, distribute, and modify it under the terms of the Free Art License. You find a copy of this license on the site www.artlibre.org and other sites.
Icons by Mark James in Creative Commons | All Credits and Attributions.

Logz Powered : http://www.logz.org | Host by Provisoire.fr | Copyleft Licence Art Libre | Vrs ?, Vxl ? | site map