Semantik · CSS · Bootstrap · Responsive

Razor, HTML og CSS

HTML-semantik og CSS i Razor-komponenter — box model, selectors, CSS isolation og Bootstrap grid til responsive Pokémon- og LoL-lister.

Læringsmål

Hvornår investere i markup/CSS? Før I binder tung API-logik — læsbar struktur gør Master/Detail og fejl-states nemmere at style (loading, tom liste, 401-banner).

Tjek dig selv før du går videre

  • Du kan forklare forskellen på semantisk HTML og div-soup.
  • Du ved hvad scoped CSS (.razor.css) gør.
  • Du har besvaret mindst ét quiz-spørgsmål korrekt.

I Blazor er markup stadig HTML. Razor tilføjer kun C#-udtryk (@), direktiver (@page, @inject) og kontrolstrukturer (@if, @foreach).

Opbygning af en Razor-fil
Typisk Razor-fil: direktiv, markup og @code.

Semantisk HTML

Skærm læsere og SEO (hvor relevant) profitterer fra meningsfulde tags:

<main>
  <header>
    <h1>Pokédex</h1>
    <p>Data fra OpgaverAPI</p>
  </header>
  <section aria-label="Resultater">
    @foreach (var p in pokemon)
    {
      <article class="dex-card">
        <h2>@p.Name</h2>
        <img src="@p.Sprite" alt="" width="96" height="96" />
      </article>
    }
  </section>
</main>

Brug alt på Pokémon-sprites med meningsfuld tekst — tom alt="" kun hvis billedet er rent dekoration.

Box model

Hvert element er en boks: content → padding → border → margin. box-sizing: border-box (Bootstrap default) gør bredde inkl. padding — nemmere grids.

Box model — visuelt

Yderst margin, så border, padding, og content inderst.

margin
border
padding
content

Margin collapse mellem sibling cards kan «ødelægge» vertikal rytme — brug gap i flex/grid (row g-3 i Bootstrap) i stedet for kun margin på hvert kort.

Selectors og typografi

Hvornår global vs scoped? Tema, fonts og Bootstrap-import i wwwroot/app.css. Kort-specifik layout (LoL rolle-badge) i .razor.css så det ikke påvirker hele appen.

CSS isolation

Filen PokemonCard.razor.css scopes styles til komponenten via attributter Blazor genererer:

/* PokemonCard.razor.css */
.card {
  border: 1px solid var(--border, #334);
  border-radius: 12px;
  padding: 1rem;
}
.card h3 {
  font-size: 1.1rem;
  margin: 0 0 0.5rem;
}

Global CSS i wwwroot/app.css til tema, fonts og Bootstrap-import.

Elev-fejl → symptom → fix: Deep selector i global CSS rammer MudBlazor-knapper — symptom: demo ser «forkert» ud. Fix: flyt til komponent-scoped fil eller brug BEM-lignende klasser.

Bootstrap grid

<div class="container py-4">
  <div class="row g-3">
    @foreach (var c in champions)
    {
      <div class="col-12 col-md-6 col-lg-4">
        <article class="card h-100">
          <div class="card-body">
            <h3 class="card-title">@c.Name</h3>
            <p class="card-text">@c.Role</p>
          </div>
        </article>
      </div>
    }
  </div>
</div>

col-12 = fuld bredde mobil; col-md-6 = to kolonner tablet; col-lg-4 = tre på desktop.

Hvornår grid frem for flex? Når I viser mange ens kort (Pokémon, LoL) i responsivt raster — g-3 gap erstatter manuel margin mellem cards.

@page "/pokemon-kort"

<article class="card">
  <h2>@navn</h2>
  <img src="@sprite" alt="@navn" width="96" height="96" />
  <ul>
    @foreach (var t in types)
    {
      <li>@t</li>
    }
  </ul>
</article>

@code {
  string navn = "Pikachu";
  string sprite = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png";
  string[] types = ["electric"];
}

Quiz 1

Hvor scopes styles til kun ét Razor-komponent?

Quiz 2

Hvilket element bør wrappe hovedindholdet på en side (accessibility)?

Hvorfor det betyder noget: Dårlig semantik og global CSS gør Pokémon-liste og LoL-grid umulige at vedligeholde i gruppeprojekt.

Sådan fejler det i praksis: Scoped CSS overskrives af global bootstrap uden ::deep — «hvorfor virker min styling ikke?»

Mini-opgave

Lav PokemonBadge.razor med semantisk <article>, scoped CSS til type-farve, tre mock-navne — uden inline styles på root.

Quiz 3

Hvor hører styling til én PokemonCard typisk hjemme?

Læs hos Microsoft

Prøv med API

  • Hent data fra Pokémon-demo og tegn et responsivt grid med semantisk HTML.
  • Sammenlign med LoL — samme grid, anden DTO.
16476 #316476 #416476 #616476 #716476 #816476 #9

Baseret på MAGS Blazor-wiki og Microsoft Learn — Blazor.