注意:我刚刚翻译了下面的文字并将其发布在这里。参考文献在本文末尾。
CSS 是一种高度专业化的编程语言,专注于样式系统。由于这个单一用例及其声明性,有时很难理解。有些人甚至否认它是一种编程语言。让我们通过编写一个智能且灵活的样式系统来证明他们是错误的。
更传统和通用的语言(如 JavaScript)为我们提供了“条件”(if/then)、“循环”(for、while)、“逻辑门”(===、&& 等)等工具.) 和“变量”。这些结构在 CSS 中的命名不同,它们的语法也非常不同,以更好地适应文档样式化的特定用例,其中一些结构直到几年前才在 CSS 中可用。
变量是最直接的。它们在 CSS 中被称为 自定义属性(尽管每个人都称它们为变量,甚至是他们自己的语法)。
:root { --color: red; } span { color: var(--color, blue); }
双破折号声明一个变量并赋值。这必须发生在一个范围内,因为在选择器之外执行此操作会破坏 CSS 语法。请注意 :root 选择器,它作为全局范围起作用。
条件可以用多种方式编写,具体取决于您想要使用它们的位置。选择器具有其元素的范围,媒体查询具有全局范围并且需要它们自己的选择器。
[data-attr='true'] { /* if */ } [data-attr='false'] { /* elseif */ } :not([data-attr]) { /* else */ }
:checked { /* if */ } :not(:checked) { /* else */ }
:root { color: red; /* else */ } @media (min-width > 600px) { :root { color: blue; /* if */ } }
计数器是CSS中最直接的循环形式,但也是使用场景最受限的一种。您只能在内容属性上使用计数器,将其显示为文本。您可以在任何给定点调整“增量”、“起点”和“值”,但输出始终仅限于文本。
main { counter-reset: section; } section { counter-increment: section; counter-reset: section; } section > h2::before { content: 'Headline ' counter(section) ': '; }
但是如果您想使用循环来定义重复布局模式怎么办?这种类型的循环有点晦涩:它是网格的自动填充属性。
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
这会用尽可能多的元素填充网格,同时缩放它们以填充可用空间,但在必要时将它们分成多行。只要找到网格项并将其限制为最小宽度 300px 和最大宽度为其网格容器大小的一小部分,它就会重复。看到可能比解释更容易:
最后,还有“循环选择器”。他们接受一个参数,该参数可以是一个可以非常精确地选择的公式。
section:nth-child(2n) { /* seleciona todos os elementos pares */ } section:nth-child(4n + 2) { /* seleciona a cada quarto items, iniciando a partir do segundo */ }
对于非常特殊的情况,您可以将 :nth-child() 与 :not() 结合使用,例如:
section:nth-child(3n):not(:nth-child(6)) { /* seleciona a cada 3 elementos, mas não o sexto elemento */ }
您可以将 :nth-child() 替换为 :nth-of-type() 和 :nth-last-of-type() 来更改最后示例的范围。
Ana Tudor 写了一篇关于 CSS 逻辑门的文章。 Login Gates 致力于将变量与计算相结合的想法。然后,她继续用它来建模和动画 3D 对象。这听起来像是神秘的魔法,随着文章的继续,它会变得更加疯狂,而且它通常是为什么 CSS 实际上是一种编程语言的最佳解释之一。
* + * { margin-top: 1rem; }
猫头鹰选择器选择一个项目后面的每个项目。对此应用 margin-top 可以有效地增加项目之间的间隙,就像 grid-gap 一样,但没有网格系统。这也意味着它更具可定制性。您可以覆盖边距顶部并使其适应任何类型的内容。想要每个项目之间有 1rem 的空间,但在标题之前有 3rem 的空间?使用猫头鹰选择器比在网格中更容易做到这一点。
Kevin Pennekamp 有一篇关于此的深入文章,甚至用伪代码解释了他的算法。
Podemos criar toggles em nosso código css que ligam e desligam certas regras com variables e calc. Isso nos dá condições muito versáteis.
.box { padding: 1rem 1rem 1rem calc(1rem + var(--s) * 4rem); color: hsl(0, calc(var(--s, 0) * 100%), 80%); background-color: hsl(0, calc(var(--s, 0) * 100%), 15%); border: calc(var(--s, 0) * 1px) solid hsl(0, calc(var(--s, 0) * 100%), 80%); } .icon { opacity: calc(var(--s) * 100%); transform: scale(calc(var(--s) * 100%)); }
Dependendo do valor de --s, .box habilitará ou desabilitará seus alert styles.
Vamos levar a mesma lógica um passo adiante e criar uma color variable que depende do seu contraste com a background color:
:root { --theme-hue: 210deg; --theme-sat: 30%; --theme-lit: 20%; --theme-font-threshold: 51%; --background-color: hsl(var(--theme-hue), var(--theme-sat), var(--theme-lit)); --font-color: hsl( var(--theme-hue), var(--theme-sat), clamp(10%, calc(100% - (var(--theme-lit) - var(theme-font-threshold)) * 1000), 95%) ); }
Este snippet calcula um background color a partir de valores HSL e uma font color black ou white, invertendo o valor de lightness (luminosidade) do background. Isso por si só pode resultar em baixo contraste de cor (uma fonte cinza de 40% em um background cinza de 60% é praticamente ilegível), então subtrairei um valor threshold (o ponto em que a cor muda de white para black), multiplicarei por um valor insanamente alto como 1000 e farei clamp nele entre 10% e 95%, para obter uma porcentagem de lightness válida no final. Tudo é controlável editando as quatro variáveis no início do snippet.
Este método também pode ser usado para escrever lógica de cores intrincada e themes automáticos, com base apenas em valores HSL.
Vamos combinar o que temos até agora para limpar a stylesheet. Ordenando tudo por viewports parece um pouco espaguete, mas ordenar isso por componente não parece nada melhor. Com variables, podemos ter o melhor dos dois mundos:
/* define variables */ :root { --paragraph-width: 90ch; --sidebar-width: 30ch; --layout-s: "header header" "sidebar sidebar" "main main" "footer footer"; --layout-l: "header header" "main sidebar" "footer footer"; --template-s: auto auto minmax(100%, 1fr) auto / minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width)); --template-l: auto minmax(100%, 1fr) auto / minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width)); --layout: var(--layout-s); --template: var(--template-s); --gap-width: 1rem; } /* manipula variables por viewport */ @media (min-width: 48rem) { :root { --layout: var(--layout-l); --template: var(--template-l); } } /* realiza o bind no DOM */ body { display: grid; grid-template: var(--template); grid-template-areas: var(--layout); grid-gap: var(--gap-width); justify-content: center; min-height: 100vh; max-width: calc( var(--paragraph-width) + var(--sidebar-width) + var(--gap-width) ); padding: 0 var(--gap-width); }
Todas as global variables são definidas no topo e ordenadas por viewport. Essa seção efetivamente se torna a Definition of Behavior, esclarecendo questões como:
Abaixo estão as definições de regras, ordenadas por componente. As Media Queries não são mais necessárias aqui, porque elas já estão definidas no topo e colocadas em variables. Podemos simplesmente codificar em nossas stylesheets sem interrupções neste ponto.
Um caso especial de pseudo classes é o :target selector, que pode ler o hash fragment da URL. Aqui está uma demonstração que usa essa mecânica para simular uma experiência semelhante a SPA:
Eu escrevi um post sobre isso. Só esteja ciente de que isso tem algumas implicações sérias de acessibilidade e precisa de alguma mecânica JavaScript para realmente ser livre de barreiras. Não faça isso em um live environment.
Manipular CSS variables se tornou uma ferramenta muito poderosa agora. Também podemos aproveitar isso em JavaScript:
// configura --s em :root document.documentElement.style.setProperty('--s', e.target.value); // configura --s scoped para #myID const el = document.querySelector('#myID'); el.style.setProperty('--s', e.target.value); // lê variables de um element const switch = getComputedStyle(el).getPropertyValue('--s');
Os exemplos de codepen acima funcionam exatamente assim.
CSS é muito capaz de definir layout systems inteligentes e reativos. Suas estruturas de controle e algoritmos podem ser um pouco estranhos em comparação com outras linguagens, mas eles estão lá e estão à altura da tarefa. Vamos parar de apenas descrever alguns styles e começar a fazer eles funcionar.
Artigo escrito por Daniel Schulz
以上是用 CSS 编写逻辑的详细内容。更多信息请关注PHP中文网其他相关文章!