Feature Media

Why Spruce

Built for teams who care about details

Color swatches and design sketches on a desk.

Design styles

One markup, eight looks

Switch between minimal, brutalist, glass and more with a single attribute. Your HTML never changes.

  • Scoped to any element
  • Dark mode for every style

Explore the styles

A designer arranging interface components on a screen.

Tokens

Consistency without effort

Colors, spacing, radii and shadows come from tokens, so every component speaks the same visual language.

  • Sass functions and custom properties
  • Runtime theming with hooks

Read about tokens

A team discussing a project around a laptop.

Accessibility

Inclusive by default

Visible focus states, logical properties, reduced motion support and semantic markup in every element.

  • RTL ready
  • WCAG 2.2 AA colors

Accessibility notes

@use 'sprucecss/scss/spruce' as *;

.feature-media-block {
  padding-block: spacer-clamp('xl', 'xxl');

  &__inner {
    display: flex;
    flex-direction: column;
    gap: spacer('xl');
  }

  &__row {
    align-items: center;
    display: grid;
    gap: spacer-clamp('l', 'xl');

    @include breakpoint('md') {
      grid-template-columns: repeat(2, minmax(0, 1fr));

      &:nth-of-type(even) .feature-media-block__image {
        order: 2;
      }
    }
  }

  &__image {
    aspect-ratio: 4 / 3;
    border-radius: radius('lg');
    box-shadow: shadow('md');
    inline-size: 100%;
    object-fit: cover;
  }

  &__content {
    @include layout-stack('s');
  }

  &__eyebrow {
    color: color('primary');
    font-size: config('font-size-sm', $typography);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  &__title {
    font-size: font-size('h2');
  }

  &__points {
    list-style: none;
    padding: 0;
    @include layout-stack('xxs');

    li {
      align-items: center;
      color: color('heading');
      display: flex;
      gap: spacer('xs');
    }
  }

  &__check {
    block-size: 1.1rem;
    color: color('primary');
    inline-size: 1.1rem;
  }

  &__link {
    font-weight: 700;
    text-decoration: none;

    &:hover span {
      display: inline-block;
      translate: 0.25em 0;
    }
  }
}

[dir='rtl'] .feature-media-block__link span {
  display: inline-block;
  scale: -1 1;
}
<section class="feature-media-block" aria-labelledby="feature-media-title">
    <div class="container">
        <div class="feature-media-block__inner">
            <header class="block-heading">
                <p class="block-heading__eyebrow">Why Spruce</p>
                <h2 class="block-heading__title" id="feature-media-title">Built for teams who care about details</h2>
            </header>
            <article class="feature-media-block__row">
                <img class="feature-media-block__image" src="https://images.unsplash.com/photo-1561070791-2526d30994b5?auto=format&amp;fit=crop&amp;w=900&amp;q=70" alt="Color swatches and design sketches on a desk." width="900" height="675" loading="lazy">
                <div class="feature-media-block__content">
                    <p class="feature-media-block__eyebrow">Design styles</p>
                    <h3 class="feature-media-block__title">One markup, eight looks</h3>
                    <p>Switch between minimal, brutalist, glass and more with a single attribute. Your HTML never changes.</p>
                    <ul class="feature-media-block__points" role="list">
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Scoped to any element</li>
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Dark mode for every style</li>
                    </ul>
                    <p class="feature-media-block__more"><a class="feature-media-block__link" href="#">Explore the styles <span aria-hidden="true">→</span></a></p>
                </div>
            </article>
            <article class="feature-media-block__row">
                <img class="feature-media-block__image" src="https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&amp;fit=crop&amp;w=900&amp;q=70" alt="A designer arranging interface components on a screen." width="900" height="675" loading="lazy">
                <div class="feature-media-block__content">
                    <p class="feature-media-block__eyebrow">Tokens</p>
                    <h3 class="feature-media-block__title">Consistency without effort</h3>
                    <p>Colors, spacing, radii and shadows come from tokens, so every component speaks the same visual language.</p>
                    <ul class="feature-media-block__points" role="list">
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Sass functions and custom properties</li>
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Runtime theming with hooks</li>
                    </ul>
                    <p class="feature-media-block__more"><a class="feature-media-block__link" href="#">Read about tokens <span aria-hidden="true">→</span></a></p>
                </div>
            </article>
            <article class="feature-media-block__row">
                <img class="feature-media-block__image" src="https://images.unsplash.com/photo-1531403009284-440f080d1e12?auto=format&amp;fit=crop&amp;w=900&amp;q=70" alt="A team discussing a project around a laptop." width="900" height="675" loading="lazy">
                <div class="feature-media-block__content">
                    <p class="feature-media-block__eyebrow">Accessibility</p>
                    <h3 class="feature-media-block__title">Inclusive by default</h3>
                    <p>Visible focus states, logical properties, reduced motion support and semantic markup in every element.</p>
                    <ul class="feature-media-block__points" role="list">
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> RTL ready</li>
                        <li><svg class="feature-media-block__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> WCAG 2.2 AA colors</li>
                    </ul>
                    <p class="feature-media-block__more"><a class="feature-media-block__link" href="#">Accessibility notes <span aria-hidden="true">→</span></a></p>
                </div>
            </article>
        </div>
    </div>
</section>

Feature Media

On this page

Alternating image and text rows to explain features in depth.

Technical Details

  • Every row is an article with its own heading. The image switches sides on every even row (only visually, with order, so the reading order stays "image, text").
  • The arrow of the link is decorative and mirrors in RTL.
  • Two columns from the md breakpoint.
  • Override the content with featureMediaBlock.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.