AD JB Toolbox 01 EN

CSS Tutorial / Build a Responsive Website with HTML and CSS

You can combine semantic HTML, shared CSS variables, Flexbox navigation, and a Grid card layout to build a small responsive website. Start with readable content and a usable narrow-screen layout, then add wider-screen adjustments and visible interaction states.

Define the page and acceptance checks

Decide what content and behavior the page needs before styling. On narrow screens, navigation wraps when needed and cards form one column. More available space allows two or three columns. Limit the overall reading width so text does not become excessively long on wide screens.

Requirements Completion criteria
content structure One main title, introductory sentence, three cards, and footer are read in order.
narrow screen Menus and cards are readable without full horizontal scrolling
wide screen Cards are laid out in multiple columns while maintaining maximum body width
keyboard navigation A focus mark appears on shortcuts to the text and menu/movement links.
Content changes Even if you enter long descriptions and strings without spaces, they are not truncated due to the fixed height.
decreased movement Allows you to move as needed without smooth scrolling and decorative transitions.

This example is a static screen and there are no links on the card itself. The introduction/course menu and large navigation links move to sections of the same document. To expand your list of actual courses, put the verified post URL in the card title. There is no need to forcefully add unused forms or infinite animations to complete this exercise.

Prepare files and semantic HTML

Create index.html and style.css in the same location in an empty folder. When creating the file, make sure it is not index.html.txt due to the hidden extension and save it as UTF-8. The link tag in index.html points to style.css in the same folder. No separate installation or build is required.

learning-site/
  index.html
  style.css

First, save the entire HTML below to index.html. Even if the CSS is empty, the title, link, and card content must be read in order. header is the site head area, nav is navigation, main is the main content, and footer is the footer. Place study topic h2 and card h3 below h1 in the document. This HTML is an example of an independent file, so it is separated from the page structure that is directly attached to the WordPress body.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>A Small Learning Site</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <a class="skip-link" href="#main">Skip to main content</a>
  <header class="site-header">
    <div class="container header-inner">
      <p class="site-name">Learning Notes</p>
      <nav aria-label="Main navigation">
        <a href="#intro">About</a><a href="#lessons">Lessons</a>
      </nav>
    </div>
  </header>
  <main id="main" tabindex="-1">
    <section id="intro" class="hero" aria-labelledby="intro-title">
      <div class="container">
        <h1 id="intro-title">Learn to Build Webpages Step by Step</h1>
        <p>Structure content with HTML and adapt its appearance with CSS.</p>
        <a class="button" href="#lessons">Explore the lessons</a>
      </div>
    </section>
    <section id="lessons" class="lessons container" aria-labelledby="lessons-title">
      <h2 id="lessons-title">Learning topics</h2>
      <ul class="card-grid" role="list">
        <li><article class="card"><h3>HTML structure</h3><p>Organize content with headings and paragraphs.</p></article></li>
        <li><article class="card"><h3>CSS styles</h3><p>Adjust colors, fonts, and spacing.</p></article></li>
        <li><article class="card"><h3>Responsive layout</h3><p>Arrange cards to fit the available width.</p></article></li>
      </ul>
    </section>
  </main>
  <footer class="site-footer"><div class="container"><p>Small learning site exercise</p></div></footer>
</body>
</html>

The shortcut to the main text is connected to the ID of main. tabindex="-1" allows main to receive focus without adding it to the normal tab order. Tap a menu or shortcut to navigate to that section and ensure that keyboard navigation continues from the main content. For the purpose and composition of the shortcut, please refer to W3C text shortcut technique.

Set shared values and content width

Start style.css with the following section. Naming color variables by their roles makes it easier to change the shared accent color. border-box includes padding and borders in the declared width, simplifying sizing. Establish a base layout that can accommodate growing content instead of assigning fixed dimensions everywhere. Before changing shared values, distinguish CSS Variables: var(), Scope, Inheritance, and Fallbacks.

/* Shared values and base styles */
:root {
  --ink: #183044;
  --accent: #166b92;
  --surface: #eef6fa;
  --line: #c9dbe4;
  --focus: #164f73;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
a { color: var(--accent); text-underline-offset: .15em; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.container { width: min(100% - 2rem, 68rem); margin-inline: auto; }
.container, .card { overflow-wrap: anywhere; }

The width of the container is the smaller of “the available width minus the sum of 2rem on both sides” and 68rem. Provides left and right margins for narrow screens and maximum width for wide screens. auto for margin-inline centers the area. overflow-wrap: anywhere allows addresses or identifiers without long spaces to be replaced on a line if necessary. A distinction must be made between practice that only increases the length of a general sentence and practice that adds one long word.

If you refresh at this stage, the colors, default font, and content width will be applied, but the headers and cards will not be laid out in detail yet. If there is no change at all, check the file path before adding the back section. The concepts of fluid size and maximum width are linked to the Fluid CSS Layouts with min, max, and clamp.

Build Flexbox navigation and focus paths

Add the following section under Common Rules in style.css: The placement between the site name and the menu is managed by the header-inner, and the spacing inside the menu is managed by the nav. By separating the gap between the two positions, you can reduce the possibility of unintentional changes in the spacing between menu links when changing the entire header spacing. The basic principles of axis direction and item placement can be found in Flexbox Basics: Containers, Items, and Axes.

/* Navigation and header */
.skip-link { position: absolute; left: 1rem; top: -6rem; padding: .5rem; background: white; }
.skip-link:focus { top: 1rem; z-index: 10; }
.site-header { border-bottom: 1px solid var(--line); }
.header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem; padding-block: 1rem; }
.site-name { margin: 0; font-weight: 700; }
nav { display: flex; flex-wrap: wrap; gap: 1rem; }

flex-wrap places the item on the next line if there is not enough space. Having a two-line menu on a narrow screen is not a failure. The criteria for judging are whether there are overlapping, truncated, or unclickable links. To maintain a meaningful navigation order, order does not simply reverse the screen order.

The text shortcut is usually placed outside the top screen and made visible when it receives focus. Hiding it with display:none doesn't achieve the same purpose because it doesn't even receive keyboard focus. On the first tab, a shortcut appears, press Enter, and make sure the next tab leads to the large link in the introduction. The dark focus outline was chosen to stand out from both the white and introductory backgrounds.

Style the fluid introduction and link states

Adding the following sections completes the introductory background, title, and large navigation links. The clamp of the title size binds the minimum, floating, and maximum values. The font does not become infinitely larger as the width increases, and the font size setting, including the rem term, is also taken into consideration. A separate screen check is required to see whether it is actually easy to read when the user zooms in.

/* Introduction and navigation link */
.hero { padding-block: clamp(3rem, 8vw, 6rem); background: var(--surface); }
.hero h1 { max-width: 18ch; margin-block: 0 1rem;
  font-size: clamp(1.8rem, 1.2rem + 2vw, 3rem); line-height: 1.25; }
.hero p { max-width: 50ch; }
.button { display: inline-block; margin-top: .5rem; padding: .7rem 1rem;
  border-radius: .4rem; background: var(--accent); color: white; text-decoration: none;
  transition: background-color 180ms ease; }
.button:hover { background: #104d6a; }

The heading's max-width: 18ch uses the width of the font's “0” glyph; it does not guarantee 18 letters per line. Its line-height controls wrapped heading lines, while the introductory paragraph is limited to 50ch. This example uses system sans-serif fonts and downloads no external font.

For larger links, use a because they take you to the lessons section of the same document. If the operation was to change the state without moving the page, the button should be reviewed. Only background color transitions are used on hover, and no decorative movement or enlargement is required. Focus status can be confirmed by a common outline.

Build Grid cards that accommodate content

Add the following sections to complete your course card and footer. Remove the list's default margins and bullets, but leave the ul and li structures in the HTML. If a list with list-style: none is outside of nav, it may not be recognized as a list in Safari's accessibility tree. In the example, ul specifies role="list" to specify the list role. This condition can also be found in the MDN listing accessibility description. The reading order of HTML does not change for the arrangement of rows and columns in the Grid.

/* Cards and footer */
.lessons { padding-block: 3rem; }
.lessons h2 { margin-block: 0 1.5rem; }
.card-grid { display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem; margin: 0; padding: 0; list-style: none; }
.card-grid > li { min-width: 0; }
.card { height: 100%; padding: 1.5rem; border: 1px solid var(--line); border-radius: .5rem; }
.card h3 { margin-block: 0 .75rem; }
.card p { margin-block: 0; }
.site-footer { padding-block: 2rem; border-top: 1px solid var(--line); }
.site-footer p { margin: 0; }

CSS Grid: repeat, auto-fit, auto-fill, and Areas creates columns that can be entered, and minmax() determines the minimum size and expandable size of each column. The minimum value of min(100%, 16rem) causes the card to shrink to that width when its parent is narrower than 16rem. The free space is divided by 1fr, and since there are three actual cards, being wider does not create a fourth. See MDN repeat function and minmax function.

Under the condition that the top-level text size is 16px and the available page width is the same as the viewport, the minimum card width is 256px, the gap is 16px, and the total left and right margins are 32px. You need at least 560px of space for two columns and 832px for three columns. As the scrollbar, parent width, and font size change, the actual transition width also changes, so do not memorize it based on the device name.

A card's height of 100% is the value that fills the height of the list items in the same row. It's not a fixed pixel height, so the rows can grow as the description grows. To prevent long words from crowding out the size of the Grid item, set the min-width of li to 0 and use the card's line wrapping rules.

Add wide-screen and reduced-motion conditions

Add this section at the end of style.css. Above 64rem, the introduction background changes to a gradient. Grid continues to determine the number of card columns independently; this media query does not set that count.

/* Conditional adjustments */
@media (min-width: 64rem) {
  .hero { background: linear-gradient(100deg, var(--surface), #fff); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .button { transition: none; }
}

In the reduced motion condition, we change scrolling to instantaneous movement and also eliminate background color transitions. The purpose and focus of the link and its content are maintained. The application of conditional rules is connected to the CSS Media Queries and Content-Based Breakpoints, and the movement and accessibility check is connected to the Check Responsive CSS with Width, Zoom, and Keyboard Tests.

Run the complete stylesheet

This is a file that combines all the rules added step by step. Use this entire file to check the order of your code or start over. After saving it in the same folder as index.html, open index.html with a browser and refresh.

/* Shared values and base styles */
:root {
  --ink: #183044;
  --accent: #166b92;
  --surface: #eef6fa;
  --line: #c9dbe4;
  --focus: #164f73;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
a { color: var(--accent); text-underline-offset: .15em; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.container { width: min(100% - 2rem, 68rem); margin-inline: auto; }
.container, .card { overflow-wrap: anywhere; }

/* Navigation and header */
.skip-link { position: absolute; left: 1rem; top: -6rem; padding: .5rem; background: white; }
.skip-link:focus { top: 1rem; z-index: 10; }
.site-header { border-bottom: 1px solid var(--line); }
.header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem; padding-block: 1rem; }
.site-name { margin: 0; font-weight: 700; }
nav { display: flex; flex-wrap: wrap; gap: 1rem; }

/* Introduction and navigation link */
.hero { padding-block: clamp(3rem, 8vw, 6rem); background: var(--surface); }
.hero h1 { max-width: 18ch; margin-block: 0 1rem;
  font-size: clamp(1.8rem, 1.2rem + 2vw, 3rem); line-height: 1.25; }
.hero p { max-width: 50ch; }
.button { display: inline-block; margin-top: .5rem; padding: .7rem 1rem;
  border-radius: .4rem; background: var(--accent); color: white; text-decoration: none;
  transition: background-color 180ms ease; }
.button:hover { background: #104d6a; }

/* Cards and footer */
.lessons { padding-block: 3rem; }
.lessons h2 { margin-block: 0 1.5rem; }
.card-grid { display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem; margin: 0; padding: 0; list-style: none; }
.card-grid > li { min-width: 0; }
.card { height: 100%; padding: 1.5rem; border: 1px solid var(--line); border-radius: .5rem; }
.card h3 { margin-block: 0 .75rem; }
.card p { margin-block: 0; }
.site-footer { padding-block: 2rem; border-top: 1px solid var(--line); }
.site-footer p { margin: 0; }

/* Conditional adjustments */
@media (min-width: 64rem) {
  .hero { background: linear-gradient(100deg, var(--surface), #fff); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .button { transition: none; }
}

Change values and diagnose problems

  1. Reduce the screen width to about 390px and then widen it, keeping the original value. For small widths there should be one column, for wide widths there should be two or three columns. If the conditions described above are the same, the differences between 559px and 560px and 831px and 832px are also compared.
  2. Change only 16rem of card-grid to 20rem. Adding more columns on the same screen requires more space. After confirmation, restore to 16rem.
  3. Change only the 68rem of the container to 50rem. Even on larger screens, the overall content width becomes narrower. After confirmation, restore to 68rem.
  4. Change it to a sufficiently dark color with only a different accent. See if the link and button backgrounds change together and restore their original colors. The white button text and focus indicator should also be readable on the new background.
  5. Stretch a card description into several sentences. Make sure that the content is not truncated as the height increases and that the height of cards in the same row is organized. After practice, restore the original sentence.
  6. Insert an English string without spaces into the card. Holding anywhere changes the line inside. Just temporarily removing that line break rule can cause overflow. After comparison, both rules and sentences are restored.
  7. Move with Tab and Shift+Tab and press Enter for each link. You should be able to navigate to the introduction and study topics without needing a mouse.
  8. Reproduce motion reduction conditions. Link movement should be maintained and smooth scrolling/transitions should disappear. After confirmation, restore the reproduction settings to default.

Check that navigation, cards, focus indicators, and paragraphs remain readable when the browser is zoomed or font settings change. Temporarily enlarging html's font size in DevTools tests rem-based sizing, but it is different from browser zoom. One successful setting does not establish usability under every zoom and text-size condition.

problem Check first
No style at all File extension, saving status, relative path of link
Horizontal scrolling occurs Long words, minimum column size, parent's actual width, missing border-box
Card height is jagged Setting the height of the same row and card; Different rows do not have to be the same
No focus indicator visible Rules that overwrite the outline, whether the outline is cut off due to overflow
unwanted movement effect Actual media conditions and applied scroll-behavior·transition values

Select the problematic element in Developer Tools to see the actual calculated width, selector, and Grid columns. Instead of masking the problem by forcing all line breaks or adding overflow:hidden to the body, first fix the size and content of the overflowed element. By checking the base state, change state, and restoration state for each requirement, you can go one step further than copying the completed code and apply it to other content as well.

More in This Category
CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

Refactor a small stylesheet without changing its layout, compare nesting and cascade layers, and check relative file paths and selector specificity.

CSS Tutorial / CSS z-index and Stacking Contexts

CSS Tutorial / CSS z-index and Stacking Contexts

Inspect parent and child stacking contexts, compare real overlap examples, and distinguish stacking order from clipping problems.

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

Create a Flexbox container, distinguish direct children from nested content, and compare row, column, and their main and cross axes.

CSS Tutorial / CSS Fonts, Font Sizes, and Line Height

CSS Tutorial / CSS Fonts, Font Sizes, and Line Height

Build a readable font stack, compare line-height inheritance, and use browser tools to identify the fonts actually rendering your text.

CSS Tutorial / CSS Background Colors and Images: cover and contain

CSS Tutorial / CSS Background Colors and Images: cover and contain

Create and load a local background image, compare repetition, cover, contain, and position, and diagnose image-path and cropping problems.

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

Compare original image proportions, cover, contain, and object-position, then test responsive video sizing with a downloadable sample.

CSS Tutorial / CSS display: Block, Inline, inline-block, and Hiding

CSS Tutorial / CSS display: Block, Inline, inline-block, and Hiding

Compare block and inline sizing, replaced elements such as images, and the layout and interaction differences between common hiding techniques.

CSS Tutorial / CSS Syntax: Selectors, Declarations, Comments, and Errors

CSS Tutorial / CSS Syntax: Selectors, Declarations, Comments, and Errors

Read and write CSS rules, use comments, and distinguish syntax errors from selectors that do not match and declarations overridden by other rules.

CSS Tutorial / CSS Transforms and Transitions

CSS Tutorial / CSS Transforms and Transitions

Compare transform order and origins, add hover and keyboard transitions, and test overflow and reduced-motion behavior.

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

Choose basic selectors for a small page, combine conditions correctly, and inspect whether each rule matches the intended elements.