Core Concepts: Fills, Strokes, and Attributes

3. Core Concepts: Fills, Strokes, and Attributes

Now that you know how to draw basic shapes, let’s make them look good! This chapter focuses on styling your SVG elements using fundamental attributes for colors, borders, and transparency. We’ll also see how CSS can be integrated to manage these styles efficiently.

3.1 fill: Coloring the Inside

The fill attribute defines the color that fills the interior of an SVG shape.

Value Types:

  • Color Names: red, blue, green, purple, etc.
  • Hexadecimal Colors: #RRGGBB or #RGB (e.g., #FF0000 for red).
  • RGB Values: rgb(red, green, blue) (e.g., rgb(255, 0, 0) for red).
  • RGBA Values: rgba(red, green, blue, alpha) (e.g., rgba(255, 0, 0, 0.5) for 50% transparent red).
  • none: Makes the shape transparent (no fill).

Example:

<svg width="300" height="150" viewBox="0 0 300 150">
    <rect x="10" y="10" width="80" height="80" fill="rebeccapurple" />
    <circle cx="150" cy="50" r="40" fill="#3498db" />
    <ellipse cx="250" cy="75" rx="40" ry="60" fill="rgba(255, 99, 71, 0.7)" />
</svg>

3.2 stroke and stroke-width: Borders and Thickness

  • stroke: Defines the color of the outline (border) of an SVG shape. It accepts the same color value types as fill.
  • stroke-width: Defines the thickness of the outline. The value is a number, typically interpreted in user units (which are pixels in our basic examples unless viewBox is configured differently).

Example:

<svg width="300" height="150" viewBox="0 0 300 150">
    <rect
        x="10"
        y="10"
        width="80"
        height="80"
        fill="none"
        stroke="black"
        stroke-width="5"
    />
    <circle cx="150" cy="50" r="40" fill="lightblue" stroke="darkblue" stroke-width="8" />
    <line x1="200" y1="20" x2="280" y2="130" stroke="green" stroke-width="10" />
</svg>

Note: If fill="none", the shape will only show its stroke. If stroke="none", it will only show its fill. If both are none, the shape will be invisible!

3.3 opacity and fill-opacity / stroke-opacity: Transparency

  • opacity: Controls the overall transparency of an entire SVG element, including its fill, stroke, and any child elements. Values range from 0 (fully transparent) to 1 (fully opaque).
  • fill-opacity: Controls only the transparency of the fill color.
  • stroke-opacity: Controls only the transparency of the stroke color.

Example:

<svg width="300" height="150" viewBox="0 0 300 150">
    <!-- Red circle, 50% opaque overall -->
    <circle cx="50" cy="75" r="40" fill="red" stroke="black" stroke-width="2" opacity="0.5" />

    <!-- Green rectangle, opaque fill, 20% opaque stroke -->
    <rect
        x="120"
        y="35"
        width="80"
        height="80"
        fill="green"
        stroke="darkgreen"
        stroke-width="10"
        stroke-opacity="0.2"
    />

    <!-- Blue triangle, 30% opaque fill, 100% opaque stroke -->
    <polygon
        points="230,40 280,120 180,120"
        fill="blue"
        fill-opacity="0.3"
        stroke="navy"
        stroke-width="3"
    />
</svg>

3.4 stroke-linecap and stroke-linejoin: Line Endings and Corners

These attributes are specific to lines and the corners of polygons/paths.

  • stroke-linecap: Defines the shape used at the end of open paths (like <line> or open <path> elements).

    • butt: (Default) The stroke is cut off squarely at the endpoint.
    • round: A rounded cap is added to the end of the stroke, with a radius equal to half the stroke-width.
    • square: A square cap is added to the end of the stroke, extending beyond the endpoint by half the stroke-width.
  • stroke-linejoin: Defines the shape used at the corners or vertices of a path.

    • miter: (Default) The edges are extended until they meet, creating a sharp corner. This can be controlled by stroke-miterlimit.
    • round: A rounded corner is created.
    • bevel: A flat corner is created, effectively “cutting off” the point.

Example:

<svg width="400" height="200" viewBox="0 0 400 200">
    <!-- Lines with different line caps -->
    <line x1="20" y1="30" x2="100" y2="30" stroke="black" stroke-width="15" stroke-linecap="butt" />
    <text x="20" y="55" font-size="12">butt</text>

    <line
        x1="20"
        y1="80"
        x2="100"
        y2="80"
        stroke="black"
        stroke-width="15"
        stroke-linecap="round"
    />
    <text x="20" y="105" font-size="12">round</text>

    <line
        x1="20"
        y1="130"
        x2="100"
        y2="130"
        stroke="black"
        stroke-width="15"
        stroke-linecap="square"
    />
    <text x="20" y="155" font-size="12">square</text>

    <!-- Polygons with different line joins -->
    <polygon
        points="150,30 200,30 175,80"
        fill="lightgray"
        stroke="blue"
        stroke-width="10"
        stroke-linejoin="miter"
    />
    <text x="150" y="105" font-size="12">miter</text>

    <polygon
        points="220,30 270,30 245,80"
        fill="lightgray"
        stroke="green"
        stroke-width="10"
        stroke-linejoin="round"
    />
    <text x="220" y="105" font-size="12">round</text>

    <polygon
        points="290,30 340,30 315,80"
        fill="lightgray"
        stroke="red"
        stroke-width="10"
        stroke-linejoin="bevel"
    />
    <text x="290" y="105" font-size="12">bevel</text>
</svg>

3.5 Styling with CSS

One of the greatest strengths of SVG is its integration with CSS. You can style SVG elements using inline style attributes, <style> tags within the SVG, or external CSS files, just like HTML. This makes styling and maintaining complex SVGs much easier.

Example: Internal <style> tag

<svg width="200" height="200">
    <style>
        .my-circle {
            fill: #f39c12; /* Orange */
            stroke: #e67e22; /* Darker orange */
            stroke-width: 4px;
            opacity: 0.8;
            transition: all 0.3s ease; /* For hover effect */
        }

        .my-circle:hover {
            fill: #e74c3c; /* Red on hover */
            stroke: #c0392b; /* Darker red on hover */
            opacity: 1;
            transform: scale(1.1); /* Animate scale on hover */
            transform-origin: center;
        }

        /* All rectangles in this SVG */
        rect {
            fill: lightblue;
            stroke: blue;
            stroke-width: 2px;
        }
    </style>

    <rect x="10" y="10" width="80" height="80" />
    <circle cx="150" cy="50" r="40" class="my-circle" />
</svg>

Example: External style.css (assuming linked in index.html)

index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>SVG CSS Styling</title>
        <link rel="stylesheet" href="style.css" />
    </head>
    <body>
        <svg width="200" height="150" viewBox="0 0 200 150">
            <rect class="styled-rect" x="10" y="10" width="80" height="80" />
            <circle class="styled-circle" cx="150" cy="75" r="60" />
        </svg>
    </body>
</html>

style.css:

body {
    background-color: #f0f0f0;
}

.styled-rect {
    fill: #27ae60; /* Emerald green */
    stroke: #2ecc71;
    stroke-width: 3;
    transition: transform 0.3s ease;
    transform-origin: 50% 50%; /* Center of the rect */
}

.styled-rect:hover {
    transform: rotate(45deg);
}

.styled-circle {
    fill: #e74c3c; /* Alizarin red */
    stroke: #c0392b;
    stroke-width: 5;
    transition: r 0.3s ease;
}

.styled-circle:hover {
    r: 70; /* Increase radius on hover */
}

Notice how we can use standard CSS properties and even hover effects directly on SVG elements. Not all CSS properties apply to SVG (e.g., box-shadow isn’t directly supported, but SVG has its own filter effects for shadows), but many presentation attributes are directly styleable.

Exercises/Mini-Challenges

  1. Styling the Traffic Light:

    • Take your traffic light from the previous chapter.
    • Give the casing a dark gray fill and a thicker stroke (e.g., 5px black).
    • Make the red light slightly transparent with opacity="0.8".
    • Add a hover effect using CSS so that when you hover over the green light, its fill changes to a brighter green and its stroke-width increases.
  2. Dashboard Widget Icons:

    • Create three simple icons, e.g., a square, a circle, and a triangle.
    • Apply different fill, stroke, and stroke-width values to each.
    • Make one of the icons have stroke-linecap="round" and stroke-linejoin="round".
    • Use an internal <style> block to style these icons.
  3. Partially Visible Shapes:

    • Draw an SVG containing two overlapping shapes (e.g., a rectangle and an ellipse).
    • Make one shape’s fill-opacity half (e.g., 0.5) so you can see the overlapping part.
    • Experiment with stacking order by changing the order of the SVG elements in the HTML. (Elements drawn later appear on top).
  4. Dashed Lines with stroke-dasharray (Bonus):

    • Research the stroke-dasharray and stroke-dashoffset attributes.
    • Draw a line and a rectangle, and make their strokes dashed.
    • Can you animate the stroke-dashoffset with CSS to create a “marching ants” effect? (Hint: this often requires setting stroke-dasharray to the getTotalLength() of the path, which for basic shapes, is simply their perimeter). We’ll cover this more in animation, but it’s a good challenge!