【问题标题】:CSS :lang() selector for elements in documents of undetermined language未确定语言文档中元素的 CSS :lang() 选择器
【发布时间】:2022-01-18 02:29:09
【问题描述】:

是否可以定位没有语言集或继承的元素,即未指定(“未知”)语言的元素?

琐事

可以使用HTML lang 属性设置HTML 文档或元素语言,例如:

<html lang="en">
<h1>Dictionary</h1>
<dl>
<dt><abbr lang="en-Mors">-... - .--</abbr>
<dd><i lang="fr-Latn">à propos</i>
</dl>

或使用HTTP Content-language header中的代码:

HTTP/2 200 OK
[other headers]
Content-language: en,en-Brai,fr-Latn

<html>
<h1>Dictionary</h1>
[rest of document]

或者它早已被弃用但仍在工作 &lt;meta http-equiv&gt; 对应:

<html>
 <head>
  <meta http-equiv="content-language" content="en,en-Brai,fr-Latn">
</head>
<html>
<h1>Dictionary</h1>
[rest of document]

在任何一种情况下,使用:lang(en) CSS 选择器都会匹配示例中的主标题和所有其他没有显式lang 属性且值不相等或以“en”开头的元素。

目标

如果发送文档没有 Content-language HTTP 标头或&lt;meta&gt; 元素和没有 lang 属性,是否可以匹配那些落下的元素到不可避免的“未知”语言?

另外,在以上述任何方式设置语言的文档或 DOM 片段中,是否可以使用 lang() CSS 选择器来匹配带有 empty lang="" attribute 的元素,从而有效地“选择退出”使用语言?

HTTP/2 200 OK
[no content-language header nor meta present]

<html>
<p>I Want to select this. <span>And this.</span></p>
<p lang="">And this.</p>
<p lang="en">Not this. <span lang="">But this again.</span></p>

什么不起作用

:lang():lang(unknown):lang(''):not(:lang(*)) 都不能用于此目的。从 :not([lang]), [lang=''] 派生的选择器在逻辑上会给出带有 HTTP 内容语言标头/元数据的用例的错误否定。

回答要求

寻求答案,要么给出没有假阴性的解决方案,要么通过参考规范(或它们的缺失)确认这是不可能的,并解释为什么会这样。


注意事项:

当存在空的lang="" 属性时,使用[lang=""] 属性选择器来定位它是可行的,但考虑到有专门的:lang() 伪类用于与语言相关的东西,感觉很奇怪。

【问题讨论】:

  • 您无法使用 CSS 获取 HTTP 标头。您必须使用 JavaScript:stackoverflow.com/questions/220231/…
  • 当然,不是“直接”,而是因为例如:lang(xx) CSS 选择器匹配所有没有通过Content-language: xx HTTP 标头提供的文档中的属性设置的显式语言设置的元素,可以说你可以“间接”非常安全。

标签: css


【解决方案1】:

Edit 2021:这已被接受为错误https://bugs.chromium.org/p/chromium/issues/detail?id=1281157


我们在:lang() 规则中提供语言范围,并与语言标签匹配。他们提到了在语言范围内支持星号:

例如,包含星号的语言范围必须正确转义或引用为字符串,例如:lang(*-Latn) 或 :lang("*-Latn") ref

在 2013 年的旧草案中:

:lang() 中的每个语言范围必须是有效的 CSS 标识符 [CSS21] 或由一个星号 (* U+002A) 紧跟一个以 ASCII 连字符 (U+002D) 开头的标识符组成,用于选择器有效。 ref

但我无法让p:lang(\*-US) 在 Windows 上的 Chrome 和 Firefox 上工作。规则p:lang(en\002DUS) 有效,但p:lang(en\002D\002A) 无效。不确定浏览器对special range "*" 的支持状态。也没有提到通过Matching of Language Tags 中的特殊范围“*”匹配undefined


但是,p:lang(\*)p:not(:lang(\*)) 在 Safari 和 Chrome 中的 iPadO 上工作。在 ipad 上打开这个jsfiddle

我认为 Chromium 不支持完整的 :lang() 功能。


解决方法:如果可以接受一点 JavaScript,那么您可以尝试以下解决方案:

document.addEventListener('DOMContentLoaded', init);

function init() {
  if (!document.documentElement.lang) {
    fetchSamePageHeaders(checkHeaderLanguage);
  }
}

//make a lightweight request to the same page to get headers
function fetchSamePageHeaders(callback) {
  var request = new XMLHttpRequest();
  request.onreadystatechange = function() {
    if (request.readyState === XMLHttpRequest.DONE) {
      if (callback && typeof callback === 'function') {
        callback(request.getAllResponseHeaders());
      }
    }
  };

  // The HEAD method asks for a response identical to that 
  // of a GET request, but without the response body.
  //you can also use 'GET', 'POST' method depending on situation      
  request.open('HEAD', document.location, true);
  request.send(null);
}

function checkHeaderLanguage(headers) {
  //console.log(headers);
  headers = headers.split("\n").map(x => x.split(/: */, 2))
    .filter(x => x[0]).reduce((ac, x) => {
      ac[x[0]] = x[1];
      return ac;
    }, {});

  if (!headers['content-language']) {
    console.log('No language in response header. Marking the html tag.');
    let html = document.querySelector('html');
    html.lang = 'dummyLang';
  } else {
    console.log('The response header has language:' + headers['content-language']);
  }
}
p {
  margin: 0;
}

p[lang=""],
p:lang(dummyLang) {
  color: darkgreen;
  font-size: 2em;
}

p:lang(en\2dus)::after {
  content: '<= english';
  font-size: 0.5em;
  color: rebeccapurple;
}
<p>I Want to select this.</p>
<p lang="">And this.</p>
<p lang="en-us">Not this.</p>
<span lang='en-us'>
    <p>Also, not this.</p>
    <p lang="">But, this too.</p>
</span>


这里我们使用 JavaScript 来确定是否在 html 标记或响应标头中提到了该语言。并分配 html 标签dummyLang 语言。您可能还想检查元标记。
有关在 javascript 中获取 HTTP 标头以及此技术的优缺点的详细说明,请参阅SO discussion

【讨论】:

  • 除了您提到的优缺点讨论之外,如果p 嵌套在另一个具有lang=".." 属性的元素中,.no-lang-header p:not([lang]) 规则将无法正常工作,这将导致p继承它,但 css 规则仍然会选择它。
  • 好收获!我已经更新了答案。
  • 感谢出色的指导、分析和错误报告。总结一下:IIUC,目前(2021-12)唯一原生支持:lang("*")的浏览器核心是Safari,对吧?我假设“iPadOs”上的所有浏览器在技术上都是 WebKit 的“皮肤”,所以它说明你已经看到它在 Chrome 中工作(?)
  • 如果可以的话,还有第二个松散相关的基于意见的问题:您对(工作/有效):not(:lang("*")) 与(不工作/无效):lang("") 用于相同目的有何看法?我计划在 csswg-drafts 中提出一个问题,要求确认前者的有效性并建议可能引入后者。这是否有意义/:lang("") 匹配 &lt;el lang=""&gt; 是否有任何明显的障碍我错过了?
  • 仅供参考,提交给 CSSWG 的问题:github.com/w3c/csswg-drafts/issues/6915 至于解决 DOM 级联中的“任何”语言变化,这也是一个有趣的问题。对于没有相同 lang 值的嵌套元素的“理智”标记,可以简单地依赖 [lang] 选择器,但是是的,不是防弹的。
【解决方案2】:

我设法想出了一个解决方法,首先你可以运行一些 js 来将每个没有 lang 属性的元素的 lang 属性设置为“xyz”,然后使用 css 选择它.....

document.querySelectorAll("p").forEach(e => {
  if (e.lang == "") e.lang = "xyz";
})
p:lang(xyz) {
  color: red;
}
<p>I Want to select this.</p>
<p lang="">And this.</p>
<p lang="en">Not this.</p>

【讨论】:

  • 这将在“文档附带内容语言 HTTP 标头”场景中给出错误匹配,并为嵌套元素提供错误匹配。这实际上与使用问题中的纯 *:not([lang]), *[lang=""] { color: red } CSS 规则相同。
猜你喜欢
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多