Lesson 33 of 45 · Web pages

Colors, backgrounds and effects

Color is the first thing a visitor sees. This lesson shows how to write colors, how to paint a background with several layers and gradients, how to fit pictures into their boxes, and how to add effects such as blur, frosted glass, blending, masks and shaped text. Every example runs in the preview under it.

Color and opacity

A color is a value in one of a few notations, written inside the quotes of a property. A name such as tomato is the easiest to read and there are about 140 of them. A hex code such as #0f766e is red, green and blue as three pairs of digits, and a fourth pair adds transparency (#0f766e80). rgb(37 99 235) gives the same three channels as numbers from 0 to 255. hsl(280 70% 40%) gives a hue as an angle from 0 to 360, then saturation and lightness, which is the easiest notation to adjust by hand: keep the hue and make the lightness smaller to get a darker version. A slash adds an alpha channel to rgb and hsl, as in rgb(15 118 110 / 40%). Two special values are transparent and currentcolor, which means the color of the text.

color is the color of the text. It is inherited, so setting it on a container colors all the text inside. background color is the flat color behind the element. Always check that the two differ enough to read: body text needs a contrast ratio of at least 4.5 to 1 against its background, and a free contrast checker will tell you the number.

web-bg-colors.salam
page:
    title = "Colors and opacity"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" background = "#e2e8f0" end
    box:
        display = flex gap = 10 flex wrap = wrap
        box: background color = "tomato" color = "white" padding = 14 content = "tomato" end
        box: background color = "#0f766e" color = "white" padding = 14 content = "#0f766e" end
        box: background color = "rgb(37 99 235)" color = "white" padding = 14 content = "rgb" end
        box: background color = "hsl(280 70% 40%)" color = "white" padding = 14 content = "hsl" end
    end
    paragraph: content = "Opacity fades the whole box, a transparent color fades only the paint." end
    box:
        display = flex gap = 10
        box: opacity = 0.4 background color = "#0f766e" color = "black" font weight = "bold" padding = 14 content = "opacity 0.4" end
        box: background color = "rgb(15 118 110 / 40%)" color = "black" font weight = "bold" padding = 14 content = "alpha 40%" end
    end
end

The two boxes at the bottom of the preview look alike but behave differently. opacity is a number from 0 to 1 and it fades the whole element, text and children included, so the bold text of the left box is faded too. A transparent color such as rgb(15 118 110 / 40%) fades only that one paint and leaves the text solid. Use opacity to fade a whole card in or out, and a transparent color when the text must stay readable.

A child can never be more opaque than its parent. If a parent has opacity = 0.5, no setting on the child brings it back to full strength. If you only want a pale background, use a transparent background color instead.

The background properties

An element can have a color and any number of images behind it, and each part has its own property. background color is the flat color at the bottom. background image is a list of images or gradients painted over it. background size sets how large an image is: a width and a height, a percentage, cover (fill the box and crop the rest) or contain (show everything and leave empty bands). background position places it, and background position x and background position y set one direction each. background repeat tiles it, with the values repeat, no-repeat, repeat-x, repeat-y, space and round.

Three more properties decide where the paint goes. background origin says which box the position is measured from, and background clip says how far the paint reaches: under the border, only under the padding, or only under the content. background attachment chooses what the image is attached to: scroll keeps it with the element, fixed keeps it still while the page moves, and local moves it with the element's own scrolling content. background blend mode mixes the layers with each other and is covered below.

background is the shorthand for all of them. It takes the parts in any order, with a / between the position and the size:

box: height = 80 color = "white" background = "linear-gradient(#0ea5e9, #1d4ed8) center / cover no-repeat" content = "Shorthand" end

The shorthand resets every part you leave out. If you write background image and then, a line later, background = "#eee", the image is gone, because the shorthand sets the image to none. Use the shorthand first and the longhands after it, or use only longhands.

Several layers

Most background properties take a comma separated list, one item per layer. The first layer in the list is on top. The example paints a layer of white dots over a gradient: the first item of each list belongs to the dots, the second to the gradient. Lists are matched by position, and a short list is repeated to fit. Only the last layer can hold a plain color, which is why the shorthand puts the color at the end.

web-bg-layers.salam
const DOTS := "url('data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2718%27 height=%2718%27%3E%3Ccircle cx=%279%27 cy=%279%27 r=%272%27 fill=%27white%27 fill-opacity=%27.6%27/%3E%3C/svg%3E')"

page:
    title = "Background layers"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        height = 150
        padding = 20
        border radius = 12
        color = "white"
        font size = 22
        background image = DOTS + ", linear-gradient(135deg, #0f766e, #1d4ed8)"
        background repeat = "repeat, no-repeat"
        background size = "18px 18px, cover"
        background position = "0 0, center"
        content = "Two layers: dots on top of a gradient"
    end
    paragraph:
        content = "The first layer in the list is the one on top."
    end
end

The dots are an SVG image written straight into the page as a data URL, so there is no file to load. The characters that are special in a URL are written as percent codes: %3C for <, %3E for >, %23 for # and %27 for a single quote. Keep such a long string in a constant above the page: block and use the constant's name in the property.

The next example shows background clip and background origin on boxes with a dashed border. The three boxes at the left paint the same color under the border, only under the padding and only under the content. The last one has a gradient that starts at the outer edge of the border and not at the padding.

web-bg-clip.salam
page:
    title = "Background clip and origin"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 10 flex wrap = wrap color = "white" font weight = "bold"
        box: width = 100 padding = 12 border = "8px dashed #0f172a" background = "#0f766e" background clip = "border-box" content = "border" end
        box: width = 100 padding = 12 border = "8px dashed #0f172a" background = "#0f766e" background clip = "padding-box" content = "padding" end
        box: width = 100 padding = 12 border = "8px dashed #0f172a" background = "#0f766e" background clip = "content-box" content = "content" end
        box:
            width = 100 padding = 12 border = "8px dashed #0f172a"
            background = "linear-gradient(#f97316, #1d4ed8)"
            background origin = "border-box"
            background clip = "border-box"
            content = "origin"
        end
    end
end

Gradients

A gradient is an image made by the browser, so it goes wherever an image is accepted: background image, mask image, border image source and list style image. linear-gradient blends colors along a line: give an angle such as 90deg (a quarter turn, left to right) or a direction such as to right, then the colors. radial-gradient spreads from a point outward in a circle or an ellipse, and circle at 30% 30% moves its center. conic-gradient sweeps around a point like a clock hand and is the way to draw pie charts and color wheels. The repeating- versions repeat the pattern forever.

A color stop can have a position. Two stops at the same position make a hard edge instead of a blend, which is how the "hard stop" box draws two flat halves, and a stop written as #0f766e 0 10px covers a range, which is how the stripes are made.

web-bg-gradients.salam
page:
    title = "Gradients"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = grid gap = 10 grid template columns = "repeat(auto-fit, minmax(130px, 1fr))" text align = center color = "white" font weight = "bold"
        box: height = 90 padding = 8 background = "linear-gradient(90deg, #f97316, #db2777)" content = "linear" end
        box: height = 90 padding = 8 background = "radial-gradient(circle at 30% 30%, #fde047, #ea580c)" content = "radial" end
        box: height = 90 padding = 8 background = "conic-gradient(from 0deg, #2563eb, #9333ea, #db2777, #2563eb)" content = "conic" end
        box: height = 90 padding = 8 background = "repeating-linear-gradient(45deg, #0f766e 0 10px, #134e4a 10px 20px)" content = "repeating" end
        box: height = 90 padding = 8 background = "linear-gradient(90deg, #2563eb 50%, #f59e0b 50%)" content = "hard stop" end
    end
end

A gradient can also fill letters. Give the element a gradient background, cut the background to the shape of the text with background clip = "text", and make the text color transparent so the background shows through.

web-bg-text.salam
page:
    title = "Gradient text"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    heading:
        size = 1
        font size = 56
        margin = 0
        background = "linear-gradient(90deg, #f97316, #db2777, #7c3aed)"
        background clip = "text"
        color = "transparent"
        content = "Salam"
    end
    paragraph: content = "The gradient is the background of the box, cut to the shape of the letters, and the text color is made transparent so it shows through." end
end

Fitting pictures into boxes

An image element has the size you give it with width and height, and the picture inside rarely has the same shape. object fit decides what happens. fill stretches the picture to the box and distorts it. contain shows the whole picture and leaves bands. cover fills the box and crops what does not fit, which is what you want for photos in a grid of cards. none keeps the natural size, and scale-down picks the smaller of none and contain. When a picture is cropped, object position chooses which part stays, with the same values as background position. The last picture in the example keeps its right side.

web-bg-fit.salam
const PHOTO := "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA8AgMAAADkulcnAAAADFBMVEX94Ec4vfgVgD0WZTT6OgVDAAABG0lEQVR42tWTPU7EMBBGn2eNZInGSIjaQqLaS/gIW7D38SW4BcUeIUfhCOmJFAon9mQzFKkQKewkzzPf/NldsR/h34Pvz1/AbR5MMMNoggkmE4wwH4tqAIa/KkkG8iGLCM4EHrwJHMQOgiIXlzt4VeDhXYmXcjBBIdkgbNQVSDufy3eBYgGBexExCqJA6Lk/bUDqtjlrUNriiAp0M/wqIr20AeCCy1ZUrnZwBam9+hawNFko9bRrYHWX6ujURVRbw3I43ldJFvd+H1VsoXE6w8f6//xY95cvEG30tuzP1VXQt6/5Et2hQQ28qJ7OOgjZXvDeRlFo1LUUpT3oW6VGcN5kKl172syKdImbblgWLE8QJViewEvaBwvgfgAayyTvlJJ3aQAAAABJRU5ErkJggg=="

page:
    title = "Fitting an image"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 12 flex wrap = wrap text align = center
        box:
            image: source = PHOTO alt = "fill" width = 130 height = 130 object fit = fill border = "1px solid #94a3b8" end
            paragraph: content = "fill" end
        end
        box:
            image: source = PHOTO alt = "contain" width = 130 height = 130 object fit = contain border = "1px solid #94a3b8" end
            paragraph: content = "contain" end
        end
        box:
            image: source = PHOTO alt = "cover" width = 130 height = 130 object fit = cover border = "1px solid #94a3b8" end
            paragraph: content = "cover" end
        end
        box:
            image: source = PHOTO alt = "cover right" width = 130 height = 130 object fit = cover object position = "right center" border = "1px solid #94a3b8" end
            paragraph: content = "cover, right" end
        end
    end
end

The pictures in these examples are small PNG and SVG images inside the page, because a page can use a data:image/... address anywhere an image address is accepted. Other kinds of data: address are refused by the compiler with an error, since they could run code.

image rendering chooses how a picture is resampled when it is scaled. The default is smooth. pixelated keeps hard square pixels, which is right for pixel art and QR codes. image orientation decides whether a photo is turned by the rotation its camera recorded: from-image does, and it is the default in current browsers, while none shows the pixels as stored. The newer object view box crops and zooms the visible part of a picture without changing its box, but it is not supported by every browser yet.

web-bg-pixels.salam
const ICON := "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAH0lEQVR4nGP4DwS31cvBGAQYQIzf51+AMYiNKYCuBQCwzDJ17qOzggAAAABJRU5ErkJggg=="

page:
    title = "Image rendering"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 24 text align = center
        box:
            image: source = ICON alt = "smooth" width = 128 height = 128 image rendering = auto end
            paragraph: content = "auto" end
        end
        box:
            image: source = ICON alt = "pixelated" width = 128 height = 128 image rendering = pixelated end
            paragraph: content = "pixelated" end
        end
    end
    paragraph: content = "The picture is only 4 by 4 pixels. Pixelated keeps its square edges when it is enlarged." end
end

Filters

filter applies a graphic effect to an element and everything inside it. Each effect is a function: blur(2px), grayscale(1), sepia(0.9), hue-rotate(120deg), brightness(1.3), contrast(1.4), saturate(3), invert(1), opacity(0.5) and drop-shadow(6px 6px 4px black). Write several with spaces between them and they are applied from left to right, so the order changes the result. The preview shows the same picture eight times. The component at the top of the file, Tile, takes a label and a filter, so each tile is one short line.

web-bg-filter.salam
const PHOTO := "data:image/svg+xml,%3Csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20viewBox=%270%200%20160%20100%27%3E%3Crect%20width=%27160%27%20height=%27100%27%20fill=%27%2338bdf8%27/%3E%3Ccircle%20cx=%27122%27%20cy=%2725%27%20r=%2714%27%20fill=%27%23fde047%27/%3E%3Cpath%20d=%27M0%20100L50%2040L100%20100Z%27%20fill=%27%23166534%27/%3E%3Cpath%20d=%27M60%20100L110%2055L160%20100Z%27%20fill=%27%2315803d%27/%3E%3C/svg%3E"

component Tile(label, fx):
    box:
        image: source = PHOTO alt = "" width = 120 filter = fx end
        paragraph: content = label margin = "4px 0" end
    end
end

page:
    title = "Filters"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 12 flex wrap = wrap text align = center font size = 13
        Tile: label = "none" fx = "none" end
        Tile: label = "blur(2px)" fx = "blur(2px)" end
        Tile: label = "grayscale(1)" fx = "grayscale(1)" end
        Tile: label = "sepia(0.9)" fx = "sepia(0.9)" end
        Tile: label = "hue-rotate(120deg)" fx = "hue-rotate(120deg)" end
        Tile: label = "brightness(1.3) contrast(1.4)" fx = "brightness(1.3) contrast(1.4)" end
        Tile: label = "invert(1)" fx = "invert(1)" end
        Tile: label = "saturate(3)" fx = "saturate(3)" end
    end
end

The values of a filter can change while the page runs. The next example reads two sliders and writes a new filter value to the box each time one of them moves. Try both sliders at once.

web-bg-live.salam
import dom

func change():
    blur := dom.GetValue(dom.ById("blur"))
    hue := dom.GetValue(dom.ById("hue"))
    dom.SetStyle(dom.ById("pic"), "filter", "blur(" + blur + "px) hue-rotate(" + hue + "deg)")
    dom.SetText(dom.ById("out"), "blur(" + blur + "px) hue-rotate(" + hue + "deg)")
end

page:
    title = "Live filter"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        id = "pic"
        width = 220
        height = 120
        border radius = 12
        background = "radial-gradient(circle at 70% 30%, #fde047 0 14%, transparent 15%), linear-gradient(#38bdf8, #0ea5e9 60%, #166534 60%)"
    end
    box:
        margin = "12px 0"
        label: content = "blur " end
        input: type = "range" id = "blur" min = 0 max = 10 value = 0 input = change end
    end
    box:
        label: content = "hue " end
        input: type = "range" id = "hue" min = 0 max = 360 value = 0 input = change end
    end
    paragraph: id = "out" content = "blur(0px) hue-rotate(0deg)" end
end

backdrop filter takes the same functions but applies them to what is behind the element, seen through its transparent parts. Together with a semi-transparent background it makes frosted glass. The card needs a background that is not fully opaque, otherwise there is nothing to see through.

web-bg-glass.salam
page:
    title = "Frosted glass"
    global: selector = "body" margin = 0 font family = "system-ui, sans-serif" end
    box:
        position = relative
        height = 220
        overflow = hidden
        background = "linear-gradient(120deg, #f97316, #db2777 50%, #4f46e5)"
        box: position = absolute left = 30 top = 30 width = 90 height = 90 border radius = "50%" background = "#fde047" end
        box: position = absolute right = 40 bottom = 20 width = 120 height = 120 border radius = "50%" background = "#22d3ee" end
        box:
            position = absolute left = 60 top = 60 right = 60 bottom = 40
            padding = 20
            color = "white"
            border = "1px solid rgb(255 255 255 / 50%)"
            border radius = 16
            background = "rgb(255 255 255 / 18%)"
            backdrop filter = "blur(10px) saturate(1.4)"
            heading: size = 3 margin = 0 content = "Frosted glass" end
            paragraph: content = "The circles behind this card are blurred." end
        end
    end
end

Blur is expensive for the browser, especially a large one on a large area. Use it on small elements, and keep an eye on scrolling speed on phones. drop-shadow follows the real shape of the content including transparent pixels, while box shadow (next lesson) follows the box.

Blend modes and isolation

Normally a box covers what is behind it. A blend mode mixes the two colors instead. mix blend mode works on the element itself and what is behind it, and background blend mode works between the background layers of one element. multiply always gives a darker result, as if two transparent colored films were stacked, and screen gives a lighter one. overlay, difference, color-dodge and the other modes are worth trying, because the formulas are easier to see than to read.

By default a blend reaches everything behind the element, all the way to the page. isolation = isolate turns an element into a group of its own, so the blending inside it stays inside. The left example is isolated: the two circles multiply with each other and with the white card, and nothing else on the page changes.

web-bg-blend.salam
const PHOTO := "data:image/svg+xml,%3Csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20viewBox=%270%200%20160%20100%27%3E%3Crect%20width=%27160%27%20height=%27100%27%20fill=%27%23fde68a%27/%3E%3Ccircle%20cx=%2780%27%20cy=%2750%27%20r=%2740%27%20fill=%27%23f87171%27/%3E%3C/svg%3E"

page:
    title = "Blend modes"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 24 flex wrap = wrap align items = center
        box:
            isolation = isolate position = relative width = 150 height = 110 background = "white"
            box: position = absolute left = 10 top = 10 width = 80 height = 80 border radius = "50%" background = "#06b6d4" mix blend mode = multiply end
            box: position = absolute left = 50 top = 10 width = 80 height = 80 border radius = "50%" background = "#ec4899" mix blend mode = multiply end
        end
        box:
            width = 150 height = 100
            background image = "url('" + PHOTO + "')"
            background size = "cover"
            background color = "#2563eb"
            background blend mode = "multiply"
        end
    end
    paragraph: content = "Left: two circles multiplied. Right: an image multiplied with the color under it." end
end

Clips, masks and shaped text

clip path cuts an element to a shape. Everything outside the shape is not drawn and also stops receiving clicks. The shapes are circle(50%), ellipse(50% 40% at 50% 50%), inset(10% 0 10% 0 round 20px) and polygon(...), a list of points as x and y pairs, where the star in the example has ten points. Because the cut is exact, anything drawn outside the box, such as a shadow, is cut too.

web-bg-clippath.salam
page:
    title = "Clip path"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 14 flex wrap = wrap
        box: width = 100 height = 100 background = "linear-gradient(135deg, #f97316, #db2777)" clip path = "circle(50%)" end
        box: width = 100 height = 100 background = "linear-gradient(135deg, #0ea5e9, #6366f1)" clip path = "polygon(50% 0, 100% 100%, 0 100%)" end
        box: width = 100 height = 100 background = "linear-gradient(135deg, #eab308, #f97316)" clip path = "polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)" end
        box: width = 100 height = 100 background = "linear-gradient(135deg, #10b981, #0f766e)" clip path = "inset(10% 0 10% 0 round 20px)" end
        box: width = 140 height = 100 background = "linear-gradient(135deg, #a855f7, #ec4899)" clip path = "ellipse(50% 40% at 50% 50%)" end
    end
end

mask does a similar job with soft edges. Its image decides how visible each point of the element is. Where the mask is opaque the element shows, and where it is transparent the element is hidden, so a gradient from black to transparent is a fade out. mask image, mask size, mask position, mask repeat, mask origin and mask clip work like their background cousins. mask mode chooses whether transparency (alpha) or brightness (luminance) counts, mask composite says how several mask layers combine, and mask type is only for masks drawn with the SVG mask element.

web-bg-mask.salam
const STAR := "url('data:image/svg+xml,%3Csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20viewBox=%270%200%20100%20100%27%3E%3Cpath%20d=%27M50%205L61%2038H96L68%2059L79%2093L50%2072L21%2093L32%2059L4%2038H39Z%27/%3E%3C/svg%3E')"

page:
    title = "Masks"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        display = flex gap = 16 flex wrap = wrap
        box:
            width = 160 height = 110
            background = "linear-gradient(90deg, #f97316, #7c3aed)"
            mask image = "linear-gradient(to right, black 30%, transparent)"
        end
        box:
            width = 120 height = 120
            background = "linear-gradient(135deg, #facc15, #db2777)"
            mask image = STAR
            mask size = "contain"
            mask repeat = "no-repeat"
            mask position = "center"
        end
    end
end

The last shape tool changes the text and not the box. A float normally makes text wrap around its rectangle. shape outside makes the text follow another shape, such as circle(50%), so the lines tuck in next to the curve. shape margin adds room between the shape and the words. With a picture or gradient as the shape, shape image threshold says how opaque a pixel must be to count. The shape changes only the wrapping, so the box still needs its own border radius or clip path to look round.

web-bg-shape.salam
page:
    title = "Text around a shape"
    global: selector = "body" font family = "Georgia, serif" margin = "1.5rem" max width = "34rem" line height = 1.6 end
    box:
        float = left
        width = 150
        height = 150
        margin = "0 12px 0 0"
        background = "radial-gradient(circle at 35% 35%, #fde047, #ea580c)"
        border radius = "50%"
        shape outside = "circle(50%)"
        shape margin = 10
    end
    paragraph:
        content = "Text normally wraps around the rectangle of a floated box. With shape outside it follows the circle instead, so the lines tuck in under the curve and the empty corners are used. The shape margin adds some air between the shape and the words, and this paragraph is long enough to show it on every line beside the sun."
    end
end

Colors for form controls

Browsers draw checkboxes, radio buttons, sliders and progress bars themselves. accent color recolors the active part of all of them with one property and keeps them native, so they stay accessible. caret color colors the blinking cursor inside a text field. The checkbox in the example also reacts to a click: its handler asks the browser for the box's checked property and writes the answer into a paragraph.

web-bg-forms.salam
import dom

func on_change():
    if dom.GetBool(dom.ById("agree"), "checked"):
        dom.SetText(dom.ById("state"), "Accepted")
    else:
        dom.SetText(dom.ById("state"), "Not accepted")
    end
end

page:
    title = "Accent and caret color"
    global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
    box:
        input: type = "checkbox" id = "agree" accent color = "#db2777" change = on_change end
        label: for = "agree" content = " I accept the terms" end
    end
    paragraph: id = "state" content = "Not accepted" end
    input: type = "text" caret color = "#db2777" placeholder = "Click and type, the caret is pink" width = 260 padding = 8 end
end

Do not use color as the only way to say something. Red text for an error is invisible to a person who cannot tell red from green, so add a word or an icon as well. In a page that supports dark mode, test every color pair in both themes.

Reference: colors, backgrounds and effects

Every property of this lesson is listed below with what it accepts and a short example. The examples are checked by the compiler, so you can paste any of them into a page: block. If a value does not belong to the property, the build stops with an error that names the property and the value, so typing mistakes are found before the page is ever opened. How that works is explained in the next lesson.

Color and opacity

PropertyWhat it does and what it acceptsExample
color
رنگ
color
The color of the text, and the default color of borders and shadows of the element. It is inherited, so setting it on a container colors all the text inside. Notations: names (crimson), hex (#be123c), rgb(), hsl() and more. [color]paragraph: color = "#be123c" content = "Text in crimson" end
opacity
شفافیت
opacity
How see-through the whole element is, with all its content, from 0 (invisible) to 1 (solid). Percentages work too: 50%. It fades text and children together; use a transparent color to fade only one paint. [number / percentage]box: opacity = 0.5 padding = 16 background = "#2563eb" color = "white" content = "Half visible" end
background color
رنگ پس‌زمینه
background-color
The flat color behind the element, under any background image. It takes a color in any notation, or transparent, which is the default. [color]box: padding = 16 background color = "#dcfce7" content = "Pale green" end
accent color
رنگ تاکید
accent-color
The color the browser uses for the active part of a checkbox, a radio button, a range slider and a progress bar. It takes any color, or auto for the browser's own blue. [color / auto]input: type = "checkbox" checked = true accent color = "#db2777" end
caret color
رنگ نشانگر متن
caret-color
The color of the blinking text cursor in inputs and text areas. It takes a color, or auto for the text color. [color / auto]input: type = "text" caret color = "#db2777" placeholder = "Type here" end

Background

PropertyWhat it does and what it acceptsExample
background
پس زمینه
background
Sets several background properties in one value: color, image, position, size, repeat, attachment, origin and clip. Layers are separated by commas and only the last layer may carry the color. A part you leave out gets its default. A / separates the position from the size. [comma list]box: height = 80 color = "white" background = "linear-gradient(#0ea5e9, #1d4ed8) center / cover no-repeat" content = "Shorthand" end
background image
تصویر پس‌زمینه
background-image
One or more images or gradients painted over the background color. Each is a url(...) or a gradient function, separated by commas, and the first listed is on top. none removes the image. [image / none; comma list]box: height = 80 background image = "linear-gradient(90deg, #f43f5e, #f59e0b)" end
background size
اندازه پس‌زمینه
background-size
The size of the background image: a length or percentage for width and height, auto for the natural size, cover to fill the box (cropping) and contain to show the whole image (letterboxing). [length / percentage / auto, cover, contain; up to 2 values; comma list]box: height = 80 background image = "linear-gradient(135deg, #f97316 50%, #fed7aa 50%)" background size = "30px 30px" end
background position
موقعیت پس‌زمینه
background-position
Where the background image sits inside the box. It takes one or two values, or up to four to measure from chosen edges (right 20px bottom 10px). Keywords are left, center, right, top and bottom; lengths and percentages work too. [length / percentage; up to 4 values; comma list]box: height = 100 background image = "radial-gradient(circle, #f43f5e 0 20px, transparent 21px)" background repeat = "no-repeat" background position = "right 20px bottom 10px" content = "Dot near the corner" end
background position x
موقعیت افقی پس‌زمینه
background-position-x
Only the horizontal position of the background. It takes left, center, right, a length or a percentage, and 0% is the left edge. [length / percentage / left, center, right; comma list]box: height = 80 background image = "radial-gradient(circle, #6366f1 0 18px, transparent 19px)" background repeat = "no-repeat" background position x = "30%" background position y = "center" end
background position y
موقعیت عمودی پس‌زمینه
background-position-y
Only the vertical position of the background. It takes top, center, bottom, a length or a percentage, and 0% is the top edge. [length / percentage / top, center, bottom; comma list]box: height = 80 background image = "radial-gradient(circle, #10b981 0 18px, transparent 19px)" background repeat = "no-repeat" background position x = "center" background position y = "bottom" end
background repeat
تکرار پس‌زمینه
background-repeat
Whether and how the image is tiled: repeat (the default), no-repeat, repeat-x, repeat-y, space (whole tiles with gaps between) and round (tiles stretched to fit whole). Two values set the horizontal and vertical directions. [repeat, no-repeat, repeat-x, repeat-y, space, round; up to 2 values; comma list]box: height = 80 background image = "linear-gradient(90deg, #0f766e 50%, #99f6e4 50%)" background size = "40px 100%" background repeat = "repeat-x" end
background attachment
پیوست پس‌زمینه
background-attachment
Says what the background is attached to. scroll (the default) keeps it with the element, fixed keeps it still while the page scrolls, and local moves it with the element's own scrolled content. Some mobile browsers treat fixed as scroll. [scroll, fixed, local; comma list]box: height = 100 background image = "linear-gradient(#fde68a, #f59e0b)" background attachment = fixed content = "Fixed to the page" end
background origin
مبدا پس‌زمینه
background-origin
Where the position of the background is measured from: the border-box (the outer edge), the padding-box (the default) or the content-box. It matters for images that do not repeat. [border-box, padding-box, content-box; comma list]box: padding = 20 border = "10px dotted #0f766e" background image = "linear-gradient(#a7f3d0, #34d399)" background origin = "border-box" background repeat = "no-repeat" background size = "50% 100%" content = "Starts at the border" end
background clip
برش پس‌زمینه
background-clip
How far the background is painted: border-box (under the border, the default), padding-box, content-box, or text, which paints only inside the letters and is used for gradient text with a transparent color. [border-box, padding-box, content-box, text; comma list]box: padding = 16 border = "8px dashed #334155" background = "#fde68a" background clip = "padding-box" content = "Paint stops at the padding" end

Images

PropertyWhat it does and what it acceptsExample
object fit
جاگیری شیء
object-fit
How an image or video fills its box when the box has a different shape: fill (stretch, the default), contain (all of it, with empty bands), cover (fill the box, crop the rest), none (natural size) and scale-down (the smaller of none and contain). [fill, contain, cover, none, scale-down]image: source = "/photo.jpg" alt = "A photo" width = 160 height = 100 object fit = cover end
object position
موقعیت شیء
object-position
Where the image sits inside its box when object fit leaves room or crops it, with the same values as background position. The default is 50% 50%, the center. [length / percentage; up to 4 values]image: source = "/photo.jpg" alt = "A photo" width = 160 height = 100 object fit = cover object position = "left top" end
object view box
جعبه دید شیء
object-view-box
Crops and zooms the visible part of an image or video without changing its box, using inset(), rect() or xywh(). none is the default. Support is still limited to some browsers. [inset(), xywh(), rect() / none]image: source = "/photo.jpg" alt = "A photo" width = 160 height = 100 object view box = "inset(10% 20%)" end
image rendering
نمایش تصویر
image-rendering
How an image is resampled when it is scaled: auto (smooth), smooth, high-quality, crisp-edges and pixelated, which keeps hard square pixels and suits pixel art. [auto, smooth, high-quality, crisp-edges, pixelated]image: source = "/icon-16.png" alt = "" width = 64 image rendering = pixelated end
image orientation
جهت‌گیری تصویر
image-orientation
Whether an image is turned according to the rotation stored in the photo by the camera. from-image (the default in current browsers) respects it and none shows the pixels as they are saved. [from-image, none]image: source = "/photo.jpg" alt = "A photo" width = 160 image orientation = "from-image" end

Filters and blending

PropertyWhat it does and what it acceptsExample
filter
پالایه
filter
Applies graphic effects to the element and everything in it: blur(), brightness(), contrast(), grayscale(), hue-rotate(), invert(), opacity(), saturate(), sepia() and drop-shadow(). List several, separated by spaces, and they apply from left to right. [up to 99 values]box: width = 80 height = 80 background = "linear-gradient(135deg, #f97316, #7c3aed)" filter = "hue-rotate(90deg) saturate(1.5)" end
backdrop filter
backdrop filter
backdrop-filter
Applies a filter to what is behind the element, which shows through the element's transparent parts. It takes the same functions as filter. The usual use is a frosted glass card: a blur together with a semi-transparent background. [up to 99 values]box: padding = 20 background = "rgb(255 255 255 / 25%)" backdrop filter = "blur(8px)" content = "Glass" end
mix blend mode
حالت آمیختگی
mix-blend-mode
How the element mixes with whatever is behind it: normal, multiply (darker), screen (lighter), overlay, difference, color-dodge and more. Put isolation on a parent to keep the effect inside it. [normal, multiply, screen, overlay, darken, lighten, ...]box: width = 80 height = 80 background = "#ec4899" mix blend mode = multiply end
background blend mode
حالت آمیختگی پس‌زمینه
background-blend-mode
How the layers of one element's background mix with each other and with its background color: normal, multiply, screen, overlay, darken, lighten and more. One mode per layer, separated by commas. [normal, multiply, screen, overlay, darken, lighten, ...; comma list]box: height = 80 background color = "#f97316" background image = "linear-gradient(#22d3ee, #6366f1)" background blend mode = "multiply" end
isolation
جداسازی
isolation
isolate makes the element a group of its own, so blend modes inside it mix only with what is inside and not with the page behind. auto is the default. [auto, isolate]box: isolation = isolate position = relative padding = 16 content = "Blends stay inside this box" end

Clip, mask and shape

PropertyWhat it does and what it acceptsExample
clip path
مسیر برش
clip-path
Cuts the element to a shape; everything outside is not drawn and does not receive clicks. Shapes are circle(), ellipse(), inset(), polygon() and path(), with none as the default. [CSS-wide keywords only]box: width = 100 height = 100 background = "#7c3aed" clip path = "polygon(50% 0, 100% 100%, 0 100%)" end
mask
ماسک
mask
The shorthand for the mask properties: image, mode, position, size, repeat, origin, clip and composite in one value. Where the mask is opaque the element shows, where it is transparent the element is hidden. [comma list]box: width = 140 height = 80 background = "#0f766e" mask = "linear-gradient(black, transparent) center / 100% 100% no-repeat" end
mask clip
برش ماسک
mask-clip
How far the mask reaches: border-box (the default), padding-box, content-box, or no-clip for no limit. Outside that area the element is hidden. [border-box, padding-box, content-box, no-clip, fill-box, stroke-box, ...; comma list]box: padding = 20 background = "#0ea5e9" mask image = "linear-gradient(black, black)" mask clip = "content-box" content = "Only the content shows" end
mask composite
ترکیب ماسک
mask-composite
How several mask layers combine: add (the default), subtract, intersect and exclude. With subtract the layers listed later are cut out of the earlier ones. [add, subtract, intersect, exclude; comma list]box: width = 120 height = 120 background = "#db2777" mask image = "linear-gradient(black, black), radial-gradient(circle, black 40%, transparent 41%)" mask composite = "subtract" end
mask image
تصویر ماسک
mask-image
The image or gradient used as the mask. Its transparency (or, with mask mode, its brightness) decides what shows. It takes a url(...), a gradient, or none. [image / none; comma list]box: width = 120 height = 120 background = "linear-gradient(135deg, #f59e0b, #db2777)" mask image = "radial-gradient(circle, black 60%, transparent 61%)" end
mask mode
حالت ماسک
mask-mode
What part of the mask image counts: alpha uses its transparency, luminance uses its brightness (white shows, black hides) and match-source picks one by the kind of image. [alpha, luminance, match-source; comma list]box: width = 140 height = 80 background = "#16a34a" mask image = "linear-gradient(90deg, black, white)" mask mode = "luminance" end
mask origin
مبدا ماسک
mask-origin
The box the mask position is measured from: border-box, padding-box (the default), content-box, and the SVG boxes fill-box, stroke-box and view-box. [border-box, padding-box, content-box, fill-box, stroke-box, view-box; comma list]box: padding = 20 background = "#7c3aed" mask image = "radial-gradient(circle, black 70%, transparent 71%)" mask repeat = "no-repeat" mask origin = "content-box" content = "Masked" end
mask position
موقعیت ماسک
mask-position
Where the mask image sits in the element, with the same values as background position: keywords, lengths, percentages, or up to four values. [length / percentage; up to 4 values; comma list]box: width = 140 height = 80 background = "#ea580c" mask image = "linear-gradient(black, black)" mask size = "50% 100%" mask repeat = "no-repeat" mask position = "right center" end
mask repeat
تکرار ماسک
mask-repeat
Whether the mask image is tiled, with the same values as background repeat: repeat, no-repeat, repeat-x, repeat-y, space and round. [repeat, no-repeat, repeat-x, repeat-y, space, round; up to 2 values; comma list]box: width = 160 height = 60 background = "#0891b2" mask image = "radial-gradient(circle, black 60%, transparent 61%)" mask size = "20px 20px" mask repeat = "repeat-x" end
mask size
اندازه ماسک
mask-size
The size of the mask image, with the same values as background size: lengths, percentages, auto, cover and contain. [length / percentage / auto, cover, contain; up to 2 values; comma list]box: width = 140 height = 80 background = "#be123c" mask image = "linear-gradient(black, black)" mask repeat = "no-repeat" mask size = "60% 60%" mask position = "center" end
mask type
نوع ماسک
mask-type
Only for masks drawn with an SVG <mask> element: luminance reads brightness (the default) and alpha reads transparency. For a mask image on an ordinary element use mask mode. [luminance, alpha]box: width = 100 height = 60 background = "#4f46e5" mask type = "alpha" end
shape image threshold
آستانه تصویر شکل
shape-image-threshold
With a shape outside taken from an image or gradient, the opacity above which a pixel counts as part of the shape. A number from 0 to 1; the default is 0. [number / percentage]box: float = left width = 100 height = 100 background = "#0ea5e9" shape outside = "linear-gradient(135deg, black 50%, transparent 50%)" shape image threshold = 0.5 end
shape margin
فضا شکل
shape-margin
The space between a floated element's shape outside and the text that wraps around it. A length or a percentage. [length / percentage]box: float = left width = 100 height = 100 border radius = "50%" background = "#f59e0b" shape outside = "circle(50%)" shape margin = 16 end
shape outside
بیرونی شکل
shape-outside
The shape that text wraps around, for an element with float. It takes circle(), ellipse(), inset(), polygon(), an image or gradient, or none (the box itself). It changes only the wrapping, not what is drawn: add clip path or border radius to make the picture match. [CSS-wide keywords only]box: float = left width = 100 height = 100 border radius = "50%" background = "#f59e0b" shape outside = "circle(50%)" end

Try it yourself

  • Make a hero banner with a diagonal gradient, a layer of dots on top and white text, then check that the text is easy to read.
  • Build a photo card with object fit = cover and a caption on a frosted glass strip at the bottom.
  • Draw a pie chart with one conic-gradient and a border radius of 50%. Then cut a hole in the middle with a mask image and mask composite.
  • Add a slider to the filter example that changes brightness as well.