```CSS涂鸦```
CSS-Doodle

原始链接: https://css-doodle.com/

## CSS-Doodle 选择器总结 CSS-Doodle 引入了自定义选择器,用于强大的基于网格的设计。`:doodle` 代表组件元素本身,覆盖外部 CSS。核心布局使用 `:container`,结合网格布局和可定制的 `gap`。 **关键选择器:** * **`:nth(n)`:** 像 `:nth-child(n)` 一样选择单元格。 * **`@even` & `@odd`:** 选择偶数/奇数单元格,简化 `:nth-child(even/odd)`。 * **`@at(col, row)`:** 通过列和行定位特定单元格。 * **`@random([ratio])`:** 随机选择单元格(比例 0-1,默认 0.5)。 * **`@row(n)` & `@col(n)`:** 选择整行/整列。 * **`@match(expression)`:** 基于数学表达式,使用 `x`、`y`、`i` 变量定位单元格。 **函数:** * **`@index`:** 返回单元格的索引。 * **`@pick(...)`:** 从列表中随机选择一个值。 * **`@rand(...)`:** 生成一个随机数。 * **`@calc(expr)`:** 评估计算。 * **`@shape(...)` & `@plot(...)`:** 为 `clip-path` 和背景生成形状和绘图。 * **`@shaders(...)`:** 应用 GLSL 着色器,实现复杂的视觉效果。 这些选择器和函数能够在 CSS 中实现动态、程序化的设计,允许使用最少的代码创建复杂的图案和动画。它们还支持别名以提高简洁性,并支持数学运算以进行高级自定义。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 CSS-Doodle (css-doodle.com) 18 分,作者 dsego,5小时前 | 隐藏 | 过去 | 收藏 | 讨论 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请YC | 联系 搜索:
相关文章

原文

Selectors

:doodle

The :doodle is a special selector indicates to the component element itself. Note that the styles would be over-written by your normal CSS files outside. (try to hover on the doodle)

:doodle { @grid: 5 / 8em; --s: 0; gap: 1px; } :doodle(:hover) { --s: 1; } --offset: calc(var(--s) * 100%); transform: translateY(var(--offset)); transition: .5s cubic-bezier(.175, .885, .32, 1.275); transition-delay: @rand(500ms); transform-origin: 50% 50%; background: #60569e;

:container

The :container is the container element that holds all the cells, which is using Grid Layout. You may want to set gap inside it.

:doodle { @grid: 8 / 8em; overflow: hidden; } :container { gap: 1px; transform: rotate(45deg) scale(1.5); } background: #60569e;

It inherits all the grid properties from :doodle so that's why this also works:

@nth(n, ...)

Select the nth cell like :nth-child(n) does.

:doodle { @size: 8em; gap: 1px; } background: #f5f5f5; :nth-child(1) { background: #60569e; } @nth(5) { background: #60569e; } @nth(3n + 8) { background: #e6437d; } @nth(1, 5, 3n + 8) { :after { content: @index; font-size: .8em; color: #fff; } }

@even

Select cells like :nth-child(even) but shorter.

:doodle { @size: 8em; } @even { background: #60569e; :after { content: @index; font-size: .8em; color: #fff; } }

@odd

Select cells like :nth-child(odd).

:doodle { @size: 8em; } @odd { background: #60569e; :after { content: @index; font-size: .8em; color: #fff; } }

@at(col, row)

Select cell at specific column and row.

:doodle { @size: 8em; gap: 1px; } background: #f5f5f5; @at(4, 2) { background: #60569e; :after { content: @x, @y; font-size: .5em; color: #fff; } }

@random([ ratio ])

Select cells randomly. The ratio accepts value between 0 and 1. Defaults to 0.5.

:doodle { @size: 8em; gap: 1px; } background: #f5f5f5; transition: .2s; @random { background: #60569e; :after { content: @index; font-size: .8em; color: #fff; } }

The selector can be applied multiple times.

:doodle { @grid: 16 / 8em; } margin: -.5px; @random { border-top: 1px solid #60569e; } @random { border-left: 1px solid #60569e; } @random(.2) { :after { content: ''; background: hsl(@rand(360), 60%, 70%); @size: @rand(3px); } }

@row(n, ...)

Select the nth row of the grid.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @row(3) { background: #60569e; :after { content: @row; font-size: .8em; color: #fff; } }

The odd and even is supported.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @row(even) { background: #60569e; :after { content: @row; font-size: .8em; color: #fff; } } @row(even) { :after { content: @row; font-size: .8em; color: #fff; } }

@col(n, ...)

Select the nth column of the grid.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @col(3) { background: #60569e; :after { content: @col; font-size: .8em; color: #fff; } }

You can use odd and even too.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @col(odd) { background: #60569e; :after { content: @col; font-size: .8em; color: #fff; } }

@match(expression)

Target the cells based on general Math expressions. The variable i, I, x, X, y and Y can be used without prefix @ symbol for calculation.

For convenience the symbols and have the meanings of <= and >= respectively.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @match(x ≤ y) { background: #60569e; }

The equal sign can be both = and ==.

:doodle { @size: 8em; } background: #f5f5f5; margin: .5px; @match(x = y) { background: #60569e; } @match(X-x+1 == y) { background: #60569e; }

A more complex example.

:doodle { @size: 8em; } background: #f5f5f5; @match(tan.cos.sin(x*y) > 1) { background: #60569e; }

Functions

@index

Returns the current index value of the cell.

:doodle { @size: 8em; } background: #60569e; margin: .5px; :after { content: @index; color: #fff; font-size: .8em; }

The parentheses can be omitted if the function has no parameters.

@grid: 5x1 / 8em; @place: center; @size: calc(100% / @size() * @i); z-index: calc(@size - @i); opacity: calc(1.1 - 1 / @size * @i); background: #60569e; :after { content: @index(); position: absolute; top: .2em; right: .2em; color: #fff; font-size: .6em; }

Alias: @i

@row

Returns the current row number of the cell.

:doodle { @size: 8em; } background: #60569e; margin: .5px; :after { content: @row; color: #fff; font-size: .8em; }

Alias: @y

@col

Returns the current column number of the cell.

:doodle { @size: 8em; } background: #60569e; margin: .5px; :after { content: @col; color: #fff; font-size: .8em; }

Alias: @x

@size-row

Returns the max row number of the grid.

@grid: 4x3 / 8em; background: #60569e; margin: .5px; :after { content: @row/@size-row; color: #fff; font-size: .8em; }

Alias: @Y

@size-col

Returns the max column number of the grid.

@grid: 4x3 / 8em; background: #60569e; margin: .5px; :after { content: @col/@size-col; color: #fff; font-size: .8em; }

Alias: @X

@size

Returns the total cells count of the grid.

@grid: 3 / 8em; background: #60569e; margin: .5px; :after { content: @i / @size; color: #fff; font-size: .8em; }

These numbers can be used to generate dynamic values together with calc().

@grid: 5/8em; --alpha: calc(@row * @col / @size); background: rgba(96, 86, 158, var(--alpha)); :after { content: @calc(@row * @col); color: #fff; font-size: .8em; }

Alias: @I

@pick(v1, v2,...)

Randomly pick a value from the given list.
(try to click on the doodle)

:doodle { @size: 8em; } opacity: @pick(1, .6, .3, .1); background: #60569e; :after { content: @pick(1, 2, 3, 4); color: #fff; font-size: .8em; }

It supports range format like this: [0-9a-z]

:doodle { @size: 8em; } opacity: @pick(1, .6, .3, .1); background: #60569e; :after { content: @pick([a-z]); color: #fff; font-size: .8em; }

Alias: @p

@pick-n(v1, v2,...)

Pick a value from the given list one by one.

:doodle { @size: 8em; } opacity: @pick-n(1, .6, .3, .1); background: #60569e; :after { content: @pick-n([1-4]); color: #fff; font-size: .8em; }

Alias: @pn

@pick-d(v1, v2,...)

Pick a value like @pick-n(), but with distinct random order.

:doodle { @size: 8em; } opacity: @pick-d(1, .6, .3, .1); background: #60569e; :after { content: @pick-d([a-z]); color: #fff; font-size: .8em; }

Alias: @pd

@rand(start [,end])

Returns a random value between two numbers.
(try to click the doodle)

:doodle { @size: 8em; } background: rgba(96, 86, 158, @rand(.9)); transition: .2s ease @rand(200ms); will-change: transform; transform: rotate(@rand(360deg)); clip-path: polygon( @rand(100%) 0, 100% @rand(100%), 0 @rand(100%) );

Alias: @r

@last-pick, @last-rand

Returns the last value of @pick, @pick-n, @pick-d and @rand.

@grid: 5 / 8em; background: linear-gradient( @pick-d(45deg, -45deg), @pick(#60569e, #e6437d), rgba(255, 255, 255, 0), @last-pick() );

Alias: @lp and @lr, respectively.

@repeat(times, value)

Compose the given value multiple times.
(try to click the doodle)

:doodle { @size: 8em; gap: 1px } background: #60569e; transition: .2s; transform: scale(.95); border-radius: @repeat(4, @rand(40%, 60%)); :after { content: ''; position: absolute; transition: .2s; left: @rand(20%, 80%); top: @rand(20%, 80%); @size: 5px; border-radius: 50%; background: #@repeat(6, @p([0-9a-f])); }

Alias: @rep

@multiple(times, value)

Same as @repeat(), but seperated with commas. Use capitalized @Multiple to make the values seperated with spaces.

:doodle { @size: 8em; } background: linear-gradient( @rand(360deg), @m3( @pick-n(#60569e, #e6437d, #ebbf4d) calc(@n(-1) * 100% / 3), @lp calc(@n * 100% / 3) ) );

The number closely after the function name will be regarded as the first parameter of the function, which will make the code more concise.

:doodle { @size: 8em; } background: #60569e; margin: 20%; box-shadow: @m5( calc(@n() * 2px) calc(@n * 2px) 0 0 #e6437d );

Alias: @m, @M

@n, @nx, @ny, @N

Used only inside @repeat and @m function to indicate the current repeating count: @n, current column count: @nx, current row count: @ny and the max count value: @N.

:doodle { @size: 8em; } background: radial-gradient( circle at @r(100%) @r(100%), @m20( @p(#60569e, #ebbf4d) calc(@n(-1) * 100% / @N), @lp calc(@n * 100% / @N) ) );

@stripe(color [size], ...)

Make stripe with gradients.

@grid: 5 / 8em; background: linear-gradient( @r(360deg), @stripe( #60569e, #e6437d, #ebbf4d ) );

The size for each step is optional.

:doodle { @size: 8em; } background: linear-gradient( 45deg, @stripe( #60569e 50%, #e6437d, #ebbf4d, #60569e ) );

:doodle { @size: 8em; } border-radius: 50%; background: conic-gradient( @stripe( #60569e 10%, #e6437d 20%, #ebbf4d 30%, #321f35 ) );

See more about stripe function in css-doodle.

@svg(svg)

Use SVG directly as background image.

You can also write SVG with the syntax of CSS.

See https://yuanchuan.dev/experimenting-a-new-syntax-to-write-svg.

@svg-filter(filter)

Apply SVG filters.

@<Math>

All Math functions and constants are available prefixed with '@'.

:doodle { @size: 8em; } --alpha: calc(@abs(@abs(@row - 3) + @abs(@col - 3) - 5) / 5); background: rgba( 96, 86, 158, var(--alpha) ); will-change: transform; transform: rotate(15deg) scale(var(--alpha));

You can also use π directly.

@grid: 1x60 / 8em 15em; @size: 65% 1px; justify-self: center; background: #60569e; opacity: calc(1 - @i / @size()); transform: rotate(-15deg) translateX(calc(@sin(@i / 4) * π * 10px));

@calc(expr)

Evaluate calculations.

@grid: 5 / 8em; background: #60569e; :after { content: @calc(@i * @i); color: #fff; font-size: .5em; } @odd { transform: scale(.75); }

@var(expr)

Same as native var(). Used to prevent the browser from evaluating the value inside nested vars. The example below won't work since the var(--bg) has no definition outside.

Use @var() instead.

:doodle { @grid: 5 / 8em; } --bg: #60569e; background: linear-gradient( @r(360deg), @var(--bg) 50%, #0000 0 );

@hex(num)

Transform a number into hex format.

:doodle { @size: 8em; gap: 1px } :after { content: \@hex(@rand(9632, 9687)); color: #60569e; }

@doodle(code)

Generate url() image with css-doodle code.

@grid: @p(2, 3) / 8em; background-image: @doodle( @grid: @r4 / 100%; background: @doodle( @grid: @r4 / 100%; background: @svg( viewBox: 0 0 1 1; path { d: M 0 0 L 1 0 L 1 1; fill: #60569e; } ); ); );

See: https://yuanchuan.dev/whats-new-in-css-doodle

@shaders(code)

Generate url() image with GLSL code. Currently only one uniform value is added: u_resolution.

@grid: 1 / 8em; background: @shaders( void main() { vec2 p = gl_FragCoord.xy / u_resolution.xy; FragColor = vec4(p.yx, .8, 1.); } );

The function accepts three parts. If there's no explict fragment part, all the code will be treated as fragment shader like the example above.

Multiple texture are accepted if they prefix with texture and the texture uniform names will be injected automatically.

@grid: 1 / 8em; background: @shaders( texture1 { @grid: 1 / 100%; background: linear-gradient( 45deg, @stripe.@m20.@p(#FFF4E0, #F8B501, #06ACB5, #17191D, #FC3D3C) ); } fragment { void main() { vec2 p = gl_FragCoord.xy / u_resolution.xy; vec2 c = vec2(.5, .5); vec2 uv = p.xy - c; float R = 3.141593; float len = length(uv * vec2(u_resolution.x / u_resolution.y, 1.)); float angle = atan(uv.y, uv.x) + R * smoothstep(.75, 0., len); float r = length(uv) + .1; vec2 coords = vec2(r * cos(angle), r * sin(angle)) + c; FragColor = texture(texture1, coords); } } );

See: https://yuanchuan.dev/add-shaders

@shape(commands)

Generate polygon() in string used by clip-path. For example, to make a hexagon:

@grid: 1 / 8em; background: #60569e; clip-path: @shape( points: 6; scale: .8; );

If the points value is big enough it approximately to be a circle.

@grid: 1 / 8em; background: #60569e; clip-path: @shape( points: 100; scale: .8; );

All commands
  • fill-rule nonzero | evenodd;

  • frame number for frame size;

  • points number between 3 - 3600;

  • rotate number in degree for rotation;

  • scale number for scale factor;

  • move a pair of value for translating x, y coords;

  • turn the angle between start/end point, defaults to be 1;

  • x x coordinate for cartesian equation;

  • y y coordinate for cartesian equation;

  • r polar equation;

Operations in equations
  • Operations available: +, -, *, /, %, ^.

  • All JavaScript Math functions and constants are supported. Such as sin, cos, tan, abs, pow, PI or π etc.

@grid: 1 / 8em; background: #60569e; clip-path: @shape( points: 300; r: cos(4t); scale: .8; );

See more examples here: https://css-doodle.com/shapes.

@plot(commands)

Generate two values in percent and seperated with space. The syntax is the same with @shape.

@grid: 1 / 8em; background: @m50( radial-gradient(#60569e 50%, #0000 0) @plot(r: .8) / 5px 5px no-repeat );

@grid: 50x1 / 8em; @size: 5px; border-radius: 50%; border: 1px solid #60569e; @place: @plot( r: sin(-t/2); move: 0 -.3; rotate: 90; );

联系我们 contact @ memedata.com