在CSS中生成(和解决!)
我喜欢让CSS做一些事情。这是您将在Minecraft建造计算器的解决问题的大脑训练的类型,除非您可能不会找到与Minecraft Redstone一起工作的工作,而无论您获得了多么出色的工作,而CSS技能值得真正的钱,许多通才的程序员也害怕CSS,因此研究这可能是从包装中脱颖而出的方式。另外,当您使用CSS完成不可能的情况时,所有正常的CSS任务似乎都很容易。
我在网络上阅读了有关CSS是否是Turing完整语言以及CSS和HTML是否符合编程语言的有趣讨论。我还没有决定,但是我可以说,在以标准方式支持常见的UI模式时,一些较新的CSS功能模糊了样式和功能之间的界限。
挑战自己仅使用CSS和HTML解决逻辑问题,可以迫使我们与CSS的一些新颖的,类似于CSS(例如自定义属性和逻辑功能)共度美好时光。目前尚不清楚如何仅使用CSS来构建Sudoku求解器,但是尽管想法听起来很疯狂,但基于约束的Sudoku逻辑似乎可能与CSS的声明性质兼容,因此我并没有震惊地发现其他人声称自己构建了“ CSSS3 Sudoku soloku soliver lover”。事实证明,这更像是CSS中的Sudoku验证器,而不是求解器。它还使用了一小撮JavaScript来使用文本框。
经过数天的英勇试图在纯CSS中构建一个完整的Sudoku求解器和发电机应用程序后,我学到了三件事。
- 您可以单位测试SASS功能和Mixins,这很棒。如果您大量使用并重复使用这些SASS功能,这就是它们的目的,那么它们将变得至关重要,并且可以像代码库的任何其他部分一样恐怖。他们应该在他们周围进行测试。
- Chrome Devtools在您投掷50MB生成的CSS时显示了无限的死亡者。
- 也许不可能将类似Python脚本的内容转换为纯CSS。或许。
但是,我们可以实现16平方公的sudoku求解器和生成器应用程序,您可以在下面播放,然后我们将分解其功能的工作方式。您的上帝现在在哪里,旨在给幼儿的简单难题?
值选择器
由于我们正在尝试CSS,因此我们在合同上有义务包括视觉上有趣的内容,尽管没有什么太过分了,因为Sudoku播放器似乎欣赏了一个UI,而UI则持续不断。在我看来,您在一些Sudoku应用程序上选择数字的方式可能更直观,因此我决定应用Radial菜单UI模式,该模式的历史可以追溯到Black and White Macintosh的日子,并且在现代视频游戏中仍然很受欢迎。实际上,有人为径向菜单构建了一个不错的纯CSS库,但是我喜欢React Planet,因为我喜欢它捕获其既有与周围圆圈的项目的方式,又如何吸引人的动作。我想看看我是否只能使用CSS构建类似的效果。
我从这支笔中拿出了一些虚线的圆形代码,然后使用旧的Border-Radius:50%的技巧从标签中删除了数字,然后我使用绝对定位将数字“粘贴”到虚线圆上的正确点,即使动画使其更改大小。
.context .number.top { 背景:绿色; 左翼:自动; 边缘权利:自动; 左:0; 右:0; 顶部:-12.5px; } .context .number.left { 背景:橙色; 保证金顶:自动; 保证金底:自动; 顶部:0; 底部:0; 左:-12.5px; }
动画在使其z索引更高时逐渐消失,因此可以单击。我们还将顶部和左边的余量从50%到零动画,因此圆圈从中心扩展以填充可用的空间。
@keyframes弹跳{ 0%{ z index:-1; 宽度:35%; 身高:35%; 左键:50%; 保证金顶:50%; 不透明度:0; } 100%{ z索引:2; 不透明度:1; 宽度:var(-Circle-radius); 高度:var(-Circle-radius); } }
然后,为了模拟类似于React Planet的弹性物理学,我在动画上使用Cux-Bezier()函数。网站Easings.net对使宽松功能变得容易。
。语境 { 动画:弹跳立方体bezier(.68,-0.6,.32,2.5).5s前锋; }
选择值选择的值的选择和使用无线电按钮hacks操作的值选择器的行为,以记住选择了哪些值并实现相互的排他性。 CSS-Tricks在复选框和无线电按钮hacks上有一篇出色的文章,因此我不会在此处重复此信息,但是我将根据复选框将CSS变量设置在Sudoku CSS网格级别上,因为这对于该实验的工作方式至关重要。
当我们使用变量时,我们可以在设置值时获得相同的行为,而不管是用户检查框以指定值还是拼图发生器为正方形设置相同的值。正方形和值的组合很多,因此我们使用Sass,而不是手工编写所有组合。我们还为每个值平方组合创建单独的位值,以及另一个自定义属性,以告诉我们该广场是否未解决。这是因为CSS使我们有限地将一个值与另一个值进行比较的能力有限(这是可能的,但可能很棘手)。我们正在以一开始可能看起来有些奇怪的方式定义这些价值,但是在验证一组Sudoku Square值是否可以解决时,我们的生活更加轻松。
@for $ i从1到16 { @for $ j从1到4 { #select-#{$ j} -value-square-#{$ i}:检查〜.sudoku { - 平方 - #{$ i} -unsolved:0; - -Square-#{$ i} -equals - #{$ j}:1; } } }
验证网格
Google医生告诉我们,即使只有16个正方形,也有四个数字的40亿可能组合。但是,一个程序迫使所有这些组合并输出根据Sudoku规则有效的程序表明,在4×4 Sudoku中只有288个有效解决方案,这与9×9网格中可能的有效解决方案的数量很大。只有288种可能的解决方案,这就是Sass真正可以自己进入的地方。我仍然不确定CSS是否是Turing完整的语言,但是Sass是,它为我们提供了一些适当的数据结构,例如列表。有了一点正则魔术,我们可以将上面链接的有效4×4难题的列表转换为牢固的二维列表!
$解决方案:((1,2,3,4,3,4,1,2,2,4,4,3,4,3,2,1),(3,1,2,4,2,4,2,4,1,3,3,3,4,2,4,2,4,2,3,3,3,3,3,3,3,3,3,3,1)(1,2,3,3,3,3,4,4,4,4,2,2,22,222.2,222.2,222.2,222,222,222,222,222,2后来...*/(2,4,3,1,3,1,4,4,2,4,2,1,3,1,3,2,4),(4,3,2,2,1,2,2,1,4,4,3,3,3,3,4,1,2,2,2,3,3,4));
甜的!如果我们的CSS黑客是多层应用程序,这将是我们的数据库。验证可以使用相同的方法检查行和列值,例如我们在简介中看到的9×9验证器,但是由于我们知道答案似乎不需要打扰检查块,列和行。相反,我们可以检查输入的数字是否仍然是一个有效的难题。在伪代码中,这可能看起来像:
foreach(正方形) { if(solutionsContains(S.Value,S.Index)或s.isunsolved()) { ShowValidationError(); } }
还记得我们每当选择平方值时就创建了这些怪异的变量吗?
- 平方 - #{$ i} -unsolved:0; - -Square-#{$ i} -equals - #{$ j}:1;
因此,现在我们在上述伪代码的第3行中有两个问题的答案,但是我们如何在CSS中执行逻辑或操作员?关于CSS-Tricks有一篇很棒的文章,内容涉及使用Calc()模拟CSS中的逻辑运算符,而且我不确定没有它的情况下我会想到我的Sudoku Solver中的某些代码,但是该文章中解释的某些公式会变得有些笨拙,尤其是如果您想与更多的ands and and ands and ands ands ands ands ands ands ands和Ors一起使用。例如,我们需要该伪代码的CSS等效物:
if(((squareOneEqualsOne和squaretwoequalstwo /*....*/以及squaresixteenequalsone)或(squareOneEqualsOne和squaretwoequalsone / equarequalsthree / he...* / and squaresixteenEqualsone))) { sudokuisvalid(); } }
好吧,这篇文章显示了2019年使用calc()编写了如何使用calc()进行逻辑。除了calc()之外,我们还拥有良好支持的min()和max()数学功能,可以更好地满足我们的需求。如果您Google google“ CSS Min,Max和夹具”(最后一个只是方便的糖,即Min()和Max()),您会发现许多示例显示了如何使用它们来简化流体排版。这是一种引人注目的用例,但是您可以在使用数字的任何地方使用这些数学功能,这为CSS增加了很多功能。例如,如果将位标志变量传递给CSS Min(),则相当于和。如果将相同的标志传递给CSS Max(),则相当于OR。我们可以使用以下真相表证明这一点。
我们可以对此非常复杂,尤其是当您添加有用的事实,即我们可以在min()和max()内完成任何calc()可以做的事情。 CSS刚刚迈出了自己的怪异脚本语言。现在,我们可以在CSS中的验证伪代码中实现条件。 (实际上,我们从Sass产生了这一点,因为它非常重复。)
.sudoku { -square-1匹配式puzzle-1:max(var(-square-1-------------------- square-1-equals-1,0)); -square-2匹配式puzzle-1:max(var(-square-2-无分解),var(-square-2- equals-2,0)); /*....*/ --square-16匹配式puzzle-1:max(var(-square-16---隔离),var(-square-16-equals-1,0)); - puzzle-1-found:min(-var(-square-1匹配式Puzzle-1), /*....*/ var(-square-16匹配式puzzle-1)); - 解决方案:max(-var(-puzzle-1-found),//...* / var(-puzzle-puzzle-288-found)); }
通过检查每个正方形是否尚未解决或具有从SASS 2D列表中的一个预计算解决方案中存在相同位置的值,我们可以产生一个变量,告诉我们当前定义的正方形是否存在于有效的4×4 Sudoku拼图中。现在,只要我们能找到可以在CSS中推动行为的数字,我们就可以基于CSS行为 - 解决方案。例如,为了使我们的网格无效时将其变成红色,我们可以将其放在每个正方形中:
。正方形 { 颜色:rgb(calc(255 *(1-var( - solution-found))),0,0); }
并非每个CSS属性都可以由一个数字驱动,但是许多可以驱动,而z索引和不透明度尤其是此用法的通用CSS属性。其他行为可能更棘手,但通常可以实现。例如,我想如何触发仅使用数字标志属性触发无效网格的摇动动画的问题,以便网格将摇动任何时间变得无效,但这是一个很好的例子,说明了黑客攻击CSS如何强迫您阅读规格并了解每个属性的边缘案例。我在此页面上找到了有关动画效果的解决方案。
默认值0s的值表示不应发生动画。
因此,我们可以将动画动画的动画持续时间基础 - 解决方案 - 每次使用以下数字单击一个数字时,请删除动画,每当解决方案变得无效时,动画级都可以使动画重播,否则什么也不做。
#select-#{$ j} -value -Square-#{$ i}:active { 动画:无; } #select-#{$ j} -value-square-#{$ i}:检查〜.sudoku { 动画:Shake Cupic-Bezier(.36,.07,.19,.97)calc((夹具(0,1-1-var( - solution-found),1),1)) * 1s) * 1s); }
如果我们没有CSS自定义属性,那么纯CSS Sudoku应用程序可能是不可能的,并且它们乍一看更强大。每当属性依赖更改的属性时,它们都会重新评估并更新UI,就像您从vue之类的精美JavaScript框架中获得的反应性的更简单版本。公平地说,反应性是以CSS变量的形式构建到浏览器中的!
现在,我们已经有了这种验证方法,并且我们的样式表知道在我们在sudoku中设置有效值时,我们就会在其潜意识中的解决方案,我们接近实施求解器!
解决每4×4 sudoku
还记得当我们引入这些中间变量时吗?
.sudoku { - puzzle-1-found:min(-var(-square-1匹配式Puzzle-1), /*....*/ var(-square-16匹配式puzzle-1)); }
这不仅是为了使验证代码更容易编写和理解。知道288个可能的拼图中的哪个是匹配的,这使我们能够编写求解器!
#no-solution { z索引:1; 颜色:红色; } @for $ solution-index从1到288 { label [for = solution-#{$ solide-index}] { 光标:指针; z-index:calc(var( - puzzle-#{$ solide-index} -found) *#{$ solution-index}); } #solution-#{$ solide-index}:检查〜.sudoku { @for $ square从1到16 { - 平方 - #{$ square} -solution:“#{nth(nth($ solutions,$ solutions-index),$ square),$ square)}”; - 平方 - #{$ square} - 彩色:灰色; -auto-#{$ square}:1; }
我将可选的复数放在上面的“拼图”一词中,因为如果用户没有填写许多正方形,则可能有多种有效的解决方案。我挖掘像这样的javaScript的求解器,即使您没有指定足够的值以使人类能够在不猜测的情况下解决该解决方案。
我的CSS求解器中的诀窍是,虽然“求解”按钮看起来像一个按钮,但实际上是288个广播按钮标签将一个堆叠在另一个按钮上,但所有人看起来都一样。想象一下一堆卡片:它们的背面都具有相同的设计,但前面的值不同。求解器逻辑将解决方案放在堆堆的顶部,并带有z索引,因此,如果您拿起它并读取其另一侧,您将始终具有正确的解决方案。如果有多个正确的解决方案,它仍然有效,因为我们以后在我们的有效答案列表中出现的解决方案将放在顶部,因为我们通过将标志乘以$ solution-index来计算z索引。如果不匹配解决方案,则所有求解按钮的z索引将为零,并且由于带有“无效拼图”消息的按钮的禁用版本具有一个Z索引,因此它将出现在顶部。如果拼图第一是解决方案,我们仍然会看到一个拼图一个按钮,因为无效的按钮在HTML中较早出现。
如果您还没有阅读,那么堆叠上下文可能会出乎意料的行为,因此这是一种不太明显的堆叠行为的很好的例证。
产生难题
我们可以将生成难题视为具有额外要求的求解器的另一个版本。
- 按下拼图发生器按钮时,需要将一些随机的正方形静止不动。
- 每次按下发电机按钮时,随机未解决的正方形和正确的解决方案的组合都应不同。
- 按下求解按钮应显示完整的解决方案。
- 如果用户手动解决生成的难题,我们想通过胜利屏幕奖励他们,该屏幕可以提供有关他们解决的速度的反馈。
CSS没有随机()函数(尽管SASS确实可以),因此每次按下同一按钮时,我们如何获得不同的行为可能并不明显。但是上面的求解器解释有点像扰流板,因为它已经在看起来像单个元素的按钮上做的类似的操作,但实际上取决于当前有效的解决方案。
“生成”按钮的问题是,每次点击时,我们如何获得不可预测的结果。全部归功于Alvaro Montoro在有关如何使用CSS产生看似随机价值的CSS漫步的文章。无线电按钮hacks和动画堆叠顺序的组合似乎很好地奏效了。我努力看我是否可以在没有额外加价的情况下做到这一点,但是我得出结论,这种方法是最好的,最简单的。为了重复使用求解器解释的卡片类比,这就像拼图卡的甲板一直在不景气,因此每当您拿起卡时,都会发现它的面孔不同。
我们可以将此伪随机性与Sass Random()函数提供的实际随机性结合在一起,以使我们的Sudoku游戏重播值。
@for $ j从0到287 { 标签[for = generate#{$ j}] { animation-delay:#{$ j * .35s}; } 标签[for = generate#{$ j}]:active:After { z索引:300; 宽度:100%; } #generate#{$ j}:检查〜.sudoku { $ blockcounts:(1:2,2:2,3:3:3,4:2); $ shufflesquares:(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16); @for $ square从1到16 { $ index1:随机(16); $ index2:随机(16); $ temp:nth($ shufflesquares,$ index1); $ shufflesquares:set-nth($ shufflesquares,$ index1,nth($ shufflesquares,$ index2)); $ shufflesquares:set-nth($ shufflesquares,$ index2,$ temp); } @each $ square in $ shufflesquares { $ row:ceil($ square/4); $ linter:1($ square -1)%4; $ block:if($ row< 3,1,3)if($ column 0){ $ BLOCKCOUNTS:MAP -MERGE($ blockcounts,($ block:$ count -1)); - 平方 - #{$ square} -unsolved:0; - -Square-#{$ square} -equals - #{$ val}:1; @for $ ether-value从1到4 { @if($ elet-value!= $ val){ - 平方 - #{$ square} - equals - #{$ elet-elet-value}:0; } } - 平方 - #{$ square} - 彩色:灰色; -auto-#{$ square}:1; } } } }
对于每个“块”(对于Sudoku说明了Sudoku说话的Sudoku网格,周围有较厚的边框),我们使用SASS随机选择四个正方形中的两个来解决,除了一个“ gimme”正方形,只有一个未解决的正方形。由于验证逻辑和求解器逻辑使用变量,而不是直接基于使用值选择器检查的值,因此验证和求解逻辑的行为都相同。这意味着生成的值的处理方式与用户单独选择每个值一样。
解决计时器
这是在前11秒内勾选的计时器。
我们将在稍后进入CSS进行求解计时器,但是让我们首先展示其中一位数字在没有CSS溢出的情况下,将元素设置为隐藏,并在元素周围有一个绿色边框,以显示动画的每个步骤都可以向用户看到的部分。
我们使用无限重复重复的密钥帧动画来以所需的间隔将可能的数字列表移到左侧(我们使用单个字体,以便我们可以确保每个字符都占据相同的宽度相同)。秒数将从零增加到九个,而下一个数字只能达到五个数字,每10秒增加一次,然后在两个秒的两个数字都需要重置为零之前。
每个数字都使用与CSS中的SpriteSheet动画相同的技术进行动画动画,除非动画不将图像背景移动以实现动画效果,我们正在移动包含可能数字的伪元素。
与CSS中的许多任务一样,在CSS中制作动画计数器有多种方法。但是,有些人不起作用跨浏览器,并且确实需要预处理程序来保持代码简洁。我喜欢我的方法,因为它很短。 CSS进行繁重的举重,以弄清楚何时以及如何移动到下一个数字。标记所需要做的就是创建一个占位持有人,每个数字都可以使用,为我们提供了一些介绍计时器的自由。
这是标记:
<div> <div> </div> <div>:</div> <div> </div> <div> </div> </div>
…和CSS:
.StopWatch { 文字平衡:中心; font-family:单域; 边缘底:10px; } 。象征 { 宽度:1ch; 溢出:隐藏; 显示:inline-flex; 字体大小:5ch; } .symbol:nth-child(1):: after { 动画:TENS 3600S步骤(6,End)无限; 内容:'012345'; } .symbol:nth-child(2):: after { 动画:单位600s步骤(10,端)无限; 内容:'0123456789'; } .symbol:nth-child(4):: after { 动画:60s步骤(6,端)无限; 内容:'012345'; } .symbol:nth-child(5):: after { 动画:单位10s步骤(10,端)无限; 内容:'0123456789'; } @KeyFrames单位{ 到 { 变换:Translatex(-10CH); } } @KeyFrames Tens { 到 { 变换:Translatex(-6CH); } }
您可能会注意到,柜台从一个小时后从一开始就再次开始。那是因为所有迭代计数都设置为无限。我们可以修复它,但是我认为,如果有人花一个小时解决其中一个,那么他们的问题比儿童的Sudoku难题更大。 ?
但是,不公平的是,即使用户产生了新的难题,我们即使使用相同的计时器才能继续滴答作响。我们可以重置吗?事实证明,我们已经在本文的第一步中解决了这个问题,我们使用:Active pseudo-class删除并有条件地重新添加了我们的数字选择器的动画。这次,这实际上更简单,因为每次我们点击“生成”按钮时,我们都想删除所有数字上的动画,以将它们带回零。然后,当无线电按钮不再活动时,动画将再次开始。因此,每次生成时,我们只需要重置计时器即可!
输入[名称=生成]:Active〜.StopWatch .Symbol :: after { 动画:无; }
Sudokumeter™
即使解决了难题,我也希望通过向玩家提供视觉反馈的时间性能来提供重播价值,并挑战他们更快地解决难题。我还想通过为您提供简约的循环规格来奖励您在本文中的奖励,您可以在自己的项目中重复使用。这是一支带有圆形尺度的独立笔,供您实验:
我们正在应用游戏中的胜利屏幕中使用的相同原理,除了在这支笔中,显示的额定值由无线电按钮hacks控制,而在游戏中,它受动画的控制,随着时间的流逝,该动画会慢慢移动到较低的评分。游戏中的量规使用零不透明度隐藏,并且只有在我们发现拼图已被手动解决时才显示(并暂停)。
让我们解释一下我们如何创建半圆形的幻觉,该半圆被颜色分为两侧。实际上,它是一个完整的CSS圆圈,其下半部分使用溢出:隐藏。
我们使用伪元素应用两种颜色,该元素填充了
然后,我们使用另一个装有游戏背景颜色的圆圈切成一个甜甜圈,以制作甜甜圈,然后使用Flexbox在更大圆圈内。
接下来,将其一半的容器的大小放置在整个圆圈的一半中,然后使用溢出:隐藏。
现在,如果我们旋转甜甜圈,则量规似乎在充满绿色或失去绿色,具体取决于我们是通过负还是正度旋转甜甜圈!
我们想将标签放在仪表的两端,并在它们之间进行描述,事实证明,Flexbox是一个优雅的解决方案:
#rating { 字体大小:30px; 显示:Flex; 宽度:300px; 正当:中间的空间; }
这是标记:
<div> <div>?</div> <div> </div> <div>?</div> </div>
这就是我们要定位标签所需要的。如果额定值
至于控制描述所说的内容,它类似于我们用于计时器的技巧,除非这次我们在垂直方面而不是水平进行操作,因为反馈说明具有可变的长度。但是它们总是相同的高度。
结论
我打开了这篇文章,疑问CSS是否是一种编程语言。很难说我们能够仅使用CSS来实施的逻辑不是编程,但是至少可以说,其中一些是不寻常的用法。与科技界中的许多事情一样,答案似乎是“取决于”,而且我们通过该实验了解了CSS,我们还说明了编程与技术一样重要。
没有免责声明,没有CSS黑客文章是完整的,尽管我们已经证明我们可以在CSS中实现复杂的逻辑并在此过程中学习很多东西,但大多数情况下,我们可能不应该在生产中做到这一点,因为可维护性,可访问性和其他一些以“ eRisition”结尾的单词。
但是我们还看到,有些事情(例如,我认为使用CSS变量获得的内置反应性)在CSS中非常方便,但可能要求我们在JavaScript中经过篮球,并可能使用框架。通过突破CSS的限制,我们最终创建了一个圆形量规,我认为可以合理地使用该圆形量规,甚至与达到一些JavaScript小部件相比,甚至可能是正确的事情,这些小部件可能很重并且做得超出了我们的真正需要。
在我对CSS Sudoku应用程序的愿望清单上是一个重置按钮。当前,如果您想启动新的Sudoku游戏,则必须刷新页面。这是无线电按钮hacks的固有限制,这使得CSS的黑客与常规编程不同。在一个阶段,我相信当我认为动画可以用于设置CSS变量时,我发现了一个解决方案 - 但事实证明,这是CSS Houdini的一部分,并且仅在基于铬的浏览器中支持。如果到处都得到支持时,它将打开Pandora的黑客盒子,并很有趣。在将来的文章中,我什至可以探讨为什么我们在Chrome中拥有的这一无害功能是CSS黑客的游戏规则改变者。
陪审团仍在CSS中是否可以使用完整的81平方英尺的sudoku求解器,但是如果您很好奇,请在评论中留下反馈。如果有足够的人想要它,我们可能会一起掉下那只兔子的洞,看看在此过程中可以照亮的CSS的黑暗角落。
以上是在CSS中生成(和解决!)的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

在本周的平台新闻综述中,Chrome引入了一个用于加载的新属性,Web开发人员的可访问性规范以及BBC Move

有很多分析平台可帮助您跟踪网站上的访问者和使用数据。也许最著名的是Google Analytics(广泛使用)
