clip-path: polygon( 0 0, 100% 0, 50% 1% ); background-color: hsla( calc(3.5 * @index() + 180), 80%, 70%, @rand(.8) ); animation: ani 1s cubic-bezier(.175, .885, 0.32, 1.275); animation-delay: @rand(.1s, 1.5s); animation-fill-mode: forwards; @keyframes ani { to { clip-path: polygon( 0 0, 100% 0, @rand(20%, 80%, .1) @rand(20%, 100%, .1) ); } }

< css-doodle />

A web component for drawing patterns with css.

Introduction

<css-doodle /> is based on Shadow DOM v1 and Custom Elements v1. You can use it on latest Chrome and Safari right now without polyfills.

The component will generate a grid of divs by the rules (plain CSS) inside it. You can easily manipulate those cells using CSS to come up with a graphic pattern or an animated graph. The limit is the limit of CSS itself.

Getting Started

Download css-doodle.js and put it into your web page.

You can also install from npm and import the module in javascript:

Usage

The syntax of <css-doodle /> is based on CSS and provided several extra utility functions and shorthand properties.

:doodle { @grid: 6 / 100vmax; background: #271929; } border-radius: 24%; border: 1px solid hsla( calc(@index() * 10), 80%, 80%, .5 ); transform: rotate(@pick(60deg, -60deg)) scale(1.2);

Grid

The number of rows and columns in the grid is defined by the "grid" attribute on the element, ranged from 1 to 16. It's default to be 1x1 when no value or 0 is given,

:doodle { @size: 7em; } background: #60569e; margin: .5px;

The following formats of "grid" value are recognizable:

  • grid = "0"
  • grid = "5"
  • grid = "20"
  • grid = "5x7"
  • grid = "5 x 7"
  • grid = "5,7"
  • grid = "5,7"

Selectors

:doodle

The :doodle or :host is a special selector indicates to the component element itself. Its styles will be over-written by your normal css files outside. (try to hover on the doodle)

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

@even

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

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

@odd

Select cells like :nth-child(odd).

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

@nth(n)

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

:doodle { @size: 7em; } background: #f5f5f5; margin: .5px; @nth(9) { background: #60569e; :after { content: '@index()'; font-size: .7em; color: #fff; } }

@at(x, y)

Select by coordinate.

:doodle { @size: 7em; } background: #f5f5f5; margin: .5px; @at(4, 2) { background: #60569e; :after { content: '@row(), @col()'; font-size: .5em; color: #fff; } }

@random

Select cells randomly.

:doodle { @size: 7em; } background: #f5f5f5; transition: .2s; @random { background: #60569e; :after { content: '@index()'; font-size: .7em; color: #fff; } } margin: .5px;

@row(n)

Select the nth row of the grid.

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

The odd and even is supported.

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

@col(n)

Select the nth column of the grid.

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

You can use odd and even too.

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

Properties

@grid

Another way to set the "grid" attribute but has higher priority.

:doodle { @grid: 3 / 7em; } background: #60569e; margin: .5px;

Set grid and doodle size at the same time:

:doodle { @grid: 8 / 7em; } background: #60569e; margin: .5px;

The row or column is limitted up to 256 only when the grid is 1-dimensional:

:doodle { @grid: 30x1 / 7em 12em; } transition: .2s ease; transition-delay: @rand(500ms); background: #60569e; will-change: width; width: @rand(5%, 100%); margin: .5px 0;

@size, @min-size, @max-size

Set width and height in one place.

:doodle { @grid: 1 / 7em; } @size: 10em; @size: 4em 5em; @min-size: 7em; @max-size: 7em; background: #60569e; :after { content: '7em x 7em'; color: #fff; font-size: .7em; }

@place-cell

Place cells relative to the grid.

:doodle { @grid: 1x5 / 7em; border: 1px solid #60569e; } @size: 1.6em; background: rgba(72, 74, 142, .8); @nth(1) { @place-cell: 0; } @nth(2) { @place-cell: 100% 25%; } @nth(3) { @place-cell: center; } @nth(4) { @place-cell: .8em calc(100% - .8em); } @nth(5) { @place-cell: 75% 80%; } :after { content: '@index()'; color: #fff; font-size: .7em; }

@shape

Return a shape based on clip-path and polygon().

:doodle { @grid: 7 / 7em; @shape: circle; } @even { @shape: hypocycloid 4; background: #60569e; transform: scale(2) rotate(-60deg); }

All shapes
:doodle { @grid: 8x8 / 100vmax; background: #271929; } clip-path: @shape(bud, 5); background: hsla( calc(1.5 * @index()), 70%, 70%, @rand(.8) ); transform: scale(@rand(.2, 1.5)) translate(@rand(-50%, 50%), @rand(-50%, 50%));

Functions

@index

Returns the current index value of the cell.

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

@row

Returns the current row number of the cell.

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

@col

Returns the current column number of the cell.

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

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

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

@pick(v1, v2,...)

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

:doodle { @size: 7em; } :after { content: '@pick(+, *, -, #)'; color: #60569e; }

@rand(start [,stop] [,step])

Returns a random value from the range of numbers.
(try to click the doodle)

:doodle { @size: 7em; } 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%) );

@<Math>

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

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

:doodle { @grid: 60x1 / 7em 15em; } @size: 75.8% 1px; justify-self: center; background: rgba( 96, 86, 158, calc(1 - @index() / 60) ); will-change: transform; transform: rotate(-15deg) translateX( calc(@sin(@index() / 4) * @PI() * 10px) );

@calc

Evaluate calculations.

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

@size: .8em; background: hsla(calc(360 / 60 * @index()), 80%, 80%, .4); clip-path: polygon( 50% 0, 100% 100%, 0 100%); transform: rotate(@rand(360deg)) scale(@rand(.6, 1, .1)) translate( @rand(-10em, 10em), @rand(-10em, 10em) )