如何使用CSS将“20201231123456”样式化为“20201231-123456”?

3
“20201231123456”是版本标识符,将以静态文本的形式显示在页面元素中。它很难被视觉上分解,我想知道是否可以使用纯CSS将其显示为日期和时间组件,而不需要修改HTML源中的实际值?
我尝试搜索,但要么得到2011年的结果,说这是不可能的,但有人正在研究它,要么得到建议将每个字符放入自己的span中的结果。
是否有现代的解决方案来实现这个看似简单的想法?
额外问题:为了使事情更加复杂,这将进入一个带有其他内容的长表格 - 一些版本标识符是5位数字而不是日期时间,但它们显示在相同类型的HTML元素中。 HTML元素的样式能否适应这两种格式,以便“54321”保持原样,但“20201231123456”仍然变成“20201231-123456”?

这只是一个简单的 <div>目标文本在此</div> - KlaymenDK
但是,我想要分割的是这个“单词”数字,而不是“目标文本”。 - KlaymenDK
1
我认为这是问题的核心。在CSS中,您可以样式化的最小原子粒子是元素。在您上面的示例中,您可以样式化<div>。如果您将其标记为<div><span>target</span> <span>text</span> <span>here</span></div>,则可以样式化任何或所有<span>元素。您无法样式化小于元素的内容。 - Rounin
3
正如@Rounin所说,你不能使用CSS来完成这个任务,因为这不是CSS的用途。你需要使用JavaScript来实现。通过一个for循环遍历所有的列表元素,然后检查列表项字符串的长度,在正确的位置插入破折号。 - Bastian Springer
1
@Rounin请回答,这样我就可以接受它 :) - KlaymenDK
显示剩余2条评论
3个回答

7

这里有一个CSS-only解决方案,适用于长(14个字符)和短(少于14个字符)的值:

div {
  font-family: monospace, monospace;
  width: 15ch;
  overflow: hidden;
  letter-spacing: 20ch;
  text-shadow: 
    /* the date */
    -20ch 0, -40ch 0, -60ch 0, -80ch 0, -100ch 0, -120ch 0, -140ch 0,
    /* the time */
    -159ch 0, -179ch 0, -199ch 0, -219ch 0, -239ch 0, -259ch 0;
}
<div>20201231123456</div>

<div>12345</div>

这个想法是使用等宽字体(所有字符宽度相同)和 ch 单位来使字符有序地移动。给容器设置固定宽度,然后将它们间隔足够远以使它们超出框外。最后,使用 text-shadow 逐个字符地投影。

我知道,可能会很繁琐(而且有点儿傻),但它确实起作用 :)

但如果你想在字符之间加上破折号,可以使用伪元素,如 ::before::after

div {
  font-family: monospace, monospace;
  width: 19ch;
  overflow: hidden;
  position: relative;
  letter-spacing: 20ch;
  text-shadow: 
    /* the date */
    -20ch 0, -40ch 0, -60ch 0, -80ch 0, -100ch 0, -120ch 0, -140ch 0,
    /* the time */
    -159ch 0, -179ch 0, -199ch 0, -219ch 0, -239ch 0, -259ch 0;
}

div::before {
  content: "-";
  position: absolute;
  left: 8ch;
}
<div>20201231123456</div>


现在来为你带来最棒的收尾:使用盒子的伪元素来绘制线条和冒号,完全格式化日期。但是这种方法只适用于较长的日期,不适用于更小的日期。

div {
  font-family: monospace, monospace;
  width: 19ch;
  overflow: hidden;
  position: relative;
  letter-spacing: 20ch;
  text-shadow: 
    /* the date */
    -20ch 0, -40ch 0, -60ch 0, -79ch 0, -99ch 0, -118ch 0, -138ch 0,
    /* the time */
    -157ch 0, -177ch 0, -196ch 0, -216ch 0, -235ch 0, -255ch 0;
}

div::before {
  content: "-:";
  position: absolute;
  text-shadow: 3ch 0, -12ch 0, -9ch 0;
  left: 4ch;
}
<div>20201231123456</div>


1
太棒了,这是一个很好的解决方案!此外,通过使用 :before,我们可以管理连字符div:before { content: '-'; position:absolute; left:8ch; } - Serge P
1
@SergeP 一个元素可以有多个文本阴影。通过将字母的间距设置为实际字符串大小的值以上(15 = 8日期 + 1空格 + 6时间),我确保只有一个字母/数字在div内可见文本阴影中。因此,我为每个字母都有一个文本阴影,并将其移至正确的位置。虽然并不是非常理想,但在这种情况下,它能够正常工作,而且代码量也不算太多。 - Alvaro Montoro
1
看起来'ch'单位有不错的浏览器支持,但在旧版Internet Explorer系列中只有部分支持(这对任何人都不应该感到惊讶)。非常酷的解决方案;今天学到了新东西。 :) - Roddy of the Frozen Peas
1
这太棒了。我会再等两个小时才接受你的问题,以便我可以给你一个奖金。我非常感激。 - KlaymenDK
你为什么要两次指定字体族为等宽字体? - KlaymenDK
显示剩余3条评论

1

仅使用CSS我认为这不容易实现,
使用JavaScriptString/slice MDN则很简单:

const str = "20201231123456";
const [date, time] = [str.slice(0, 8), str.slice(8)];

console.log( `${date}-${time}` )

或者像这样:

const str = "20201231123456";
const res = /^(\d{8})(\d+)$/.exec(str).splice(1).join('-');

console.log(res)


使用案例示例:

假设版本ID在一个特定的元素中,比如带有类名为.vid<span><td>元素内:

const prettyVID = el => {
  const str = el.textContent.trim();
  const [Y, M, D, h, m, s] = str.match(/^\d{4}|\d{2}/g);
  const ISO8601 = `${Y}-${M}-${D}T${h}:${m}:${s}Z`;
  const custom  = `${Y}${M}${D}-${h}${m}${s}`;

  el.title = new Date(ISO8601).toLocaleString('en', {timeZone: 'UTC'});
  el.textContent = custom;
}


document.querySelectorAll('.vid').forEach(prettyVID);
th, td {padding: 8px;}
<table>
  <thead>
    <tr><th>App name</th><th>Version (Hover to see date)</th></tr>
  </thead>
  <tbody>
    <tr><td>Lorem</td><td class="vid">20201231091015</td></tr>
    <tr><td>Ipsum</td><td class="vid">20200224123456</td></tr>
  </tbody>
</table>


0

这里的难点在于CSS不是完成此任务的正确技术。

CSS具有许多表现能力,但是...你可以在CSS中样式化的最小原子粒子是像<div><span><strong>等HTML元素。

例如,如果我们采用以下<div>元素:

<div>target text here</div>

我们可以使用CSS以任意方式呈现<div>

如果我们将其标记为:

<div><span>target</span> <span>text</span> <span>here</span></div>

然后,我们可以为任何或所有的<span>元素添加样式。

但是,我们无法为小于元素大小的标记中的任何部分添加样式。


注意:我们可以争论上面的最终陈述有一些(相当特定的)例外情况,包括 CSS 伪元素 ::first-letter::first-line


如果不能使用CSS,我们可以采用什么方法?

正如@BastianSpringer在上面的评论中所指出的那样,Javascript具有实现您想要达到的效果的能力。

工作示例:

let numbers = [...document.getElementsByClassName('number')];

for (let number of numbers) {

  numberText = number.textContent;

  if (numberText.length > 8) {
    let numberArray = numberText.split('');
    numberArray.splice(8, 0, '-');
    numberText = numberArray.join('');
    number.textContent = numberText;
  }
}
<p class="number">54321</p>
<p class="number">20201231123456</p>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接