HTML and CSS for the front-end explained: HSC Software Engineering Module 2
“Construct front-end pages using HTML for structure and CSS for presentation, including semantic markup and responsive design”
Front-end HTML uses semantic elements like <header>, <main>, <article> and <footer> to convey structure. CSS targets those elements with selectors and declarations, using the box model for layout and media queries for responsive design. The viewport meta tag plus relative units plus media queries cover mobile, tablet and desktop.
Think of building a web page like building a house. HTML is the frame and room labels: this room is the kitchen, this is the front door, this is the letterbox. Semantic elements such as <header>, <main> and <footer> are those labels, telling anyone reading the plans (a screen reader, a search engine, a browser) exactly what each part is for, rather than just "room 1, room 2, room 3" written as unlabelled <div>s. CSS is the interior decorating: paint colours, furniture layout, and how the rooms rearrange themselves depending on whether the house is viewed on a huge display or a tiny phone screen. A media query is like a smart house that automatically folds the dining table away and stacks the furniture into one narrow hallway when the walls close in, that is, when the viewport shrinks, so the house still works no matter what size box it is squeezed into.
What this dot point is asking
NESA wants you to construct a basic front-end with HTML for structure and CSS for presentation. Use semantic elements, the box model, and at least one media query for responsive design.
The answer
HTML: structure
HTML marks up content with elements. Semantic elements describe what the content is, not what it looks like:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HSC study portal</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/subjects">Subjects</a>
</nav>
</header>
<main>
<article>
<h1>How to study Physics</h1>
<p>Start with the syllabus dot points...</p>
</article>
<aside>
<h2>Related</h2>
<ul>
<li><a href="/chemistry">Chemistry guide</a></li>
</ul>
</aside>
</main>
<footer>
<p>(c) 2026 ExamExplained</p>
</footer>
</body>
</html>
Key semantic elements: <header>, <nav>, <main>, <article>, <aside>, <section>, <footer>, <figure>, <figcaption>. Use these instead of generic <div> whenever the meaning is clear. Screen readers, search engines and reader-mode browsers use the semantic tree.
CSS: presentation
CSS targets HTML elements with selectors and applies declarations:
body {
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: #1f2937;
background: #f9fafb;
margin: 0;
}
header {
background: #1e3a8a;
color: white;
padding: 1rem 2rem;
}
header nav a {
color: white;
margin-right: 1rem;
text-decoration: none;
}
main {
max-width: 70ch;
margin: 2rem auto;
padding: 0 1rem;
}
article h1 {
font-size: 2rem;
margin-bottom: 1rem;
}
The box model
Every element is a rectangular box made of content, padding, border and margin. Setting box-sizing: border-box makes width and height include padding and border, which is almost always what you want:
*, *::before, *::after {
box-sizing: border-box;
}
Every rendered HTML element is nested rectangles, from the inside out: content (text/images), then padding (space inside the border), then border (the visible edge), then margin (space outside the border, between elements). With the default box-sizing: content-box, a declared width sizes only the content box, so padding and border are added on top and can push the element wider than intended. box-sizing: border-box makes the declared width/height include padding and border, so the box never grows past the size you set.
Responsive design
Phones, tablets and desktops have very different viewports. Three tools:
The viewport meta tag (in HTML head) tells mobile browsers to use device width:
<meta name="viewport" content="width=device-width, initial-scale=1">Relative units (
rem,em,%,vw,vh) scale with the viewport and user preferences. Avoid hard-codedpxfor layout dimensions.Media queries apply rules conditionally:
@media (max-width: 600px) { main { padding: 0 0.5rem; } h1 { font-size: 1.5rem; } nav { display: flex; flex-direction: column; } }
Modern layout
Flexbox for one-dimensional layout (rows or columns):
header nav {
display: flex;
gap: 1rem;
align-items: center;
}
Grid for two-dimensional layout:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
Accessibility
Semantic markup is the first step. Also:
- Use
alttext on every image. - Pair every form input with a
<label>. - Ensure colour contrast meets WCAG AA (4.5:1 for body text).
- Make focus styles visible.
Ask "how many dimensions am I laying out?" first: a single row or column (a nav bar, a button toolbar) is Flexbox; a layout with both rows and columns that need to line up (a card gallery, a dashboard) is Grid. For media queries, pick breakpoints from where YOUR content breaks, not memorised device widths: widen a real browser window slowly and note the pixel width where text lines get uncomfortably long or elements start to crowd, then set the max-width there. Common, defensible checkpoints for HSC answers are around 600px (phone) and 900px to 1024px (tablet), but always justify the number with what happens to the content, not just "because it is a common breakpoint".
Convert the following non-semantic markup to semantic HTML and explain why each change helps.
<div class="top">
<div class="logo">ExamExplained</div>
</div>
<div class="content">
<div class="post">
<div class="title">How to study Physics</div>
<div class="body">Start with the syllabus...</div>
</div>
</div>
<div class="bottom">(c) 2026</div>
Semantic version:
<header>
<h1>ExamExplained</h1>
</header>
<main>
<article>
<h2>How to study Physics</h2>
<p>Start with the syllabus...</p>
</article>
</main>
<footer>(c) 2026</footer>
Each change is meaningful: <header> and <footer> create landmark regions for screen readers, <main> lets users skip to the main content, <article> indicates a self-contained piece, and the headings produce an outline.
- Using divs for everything
- A
div.headeris not the same as<header>for screen readers or search engines. - Forgetting the viewport meta tag
- Without it, mobile browsers zoom out to fit a desktop layout, defeating responsive CSS.
- Hard-coding pixel widths everywhere
- Fluid layouts use
%,rem,vw,max-widthand let content reflow. - Using inline styles instead of a stylesheet
- Inline styles are hard to maintain and override; use a CSS file and target elements with selectors.
Skipping <label> on form inputs. Without it, screen reader users do not know what the field is for.
Exam-style questions
Questions in the style of NESA exam questions on this dot point, each with a worked answer. They are written by ExamExplained unless tagged "Past paper"; the year shows the paper a question is modelled on.
Practice5 marksWrite HTML and CSS for a simple article page with a header, main article body and footer. Apply at least one media query so the layout adapts to a phone-sized viewport.Show worked answer →
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>School newsletter</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Year 12 newsletter</h1>
</header>
<main>
<article>
<h2>Term 2 highlights</h2>
<p>Software Engineering students built a study portal.</p>
</article>
</main>
<footer><p>(c) 2026 the school</p></footer>
</body>
</html>
body { font-family: system-ui; margin: 0; }
header, main, footer { padding: 1rem 2rem; }
main { max-width: 70ch; margin: 0 auto; }
@media (max-width: 600px) {
header, main, footer { padding: 1rem; }
h1 { font-size: 1.5rem; }
}
The HTML uses semantic elements (<header>, <main>, <article>, <footer>) so assistive tech and search engines understand structure. The viewport meta tag tells mobile browsers to use the device width. CSS controls colour, spacing and typography, with a media query reducing padding and shrinking the heading on narrow screens.
Markers reward a valid HTML5 skeleton, semantic elements (not just divs), the viewport meta tag, and a working media query with a sensible breakpoint.
Practice questions
Original practice questions graded from foundation to exam level, each with a full worked solution. Try them before revealing the solution.
foundation2 marksIdentify the semantic element that should wrap the primary, unique content of a page (not the navigation, sidebar or footer).Show worked solution →
The <main> element wraps the primary, unique content of the page. There should be only one <main> per page, and it should not include content repeated across pages such as the navigation bar, sidebars or footer.
Marking criteria: 1 mark for naming <main>, 1 mark for explaining it holds the page's unique content (excluding repeated regions).
foundation3 marksRewrite the following CSS rule so that padding and border are included inside the declared width, and state the property that achieves this.Show worked solution →
.card {
box-sizing: border-box;
width: 300px;
padding: 1rem;
border: 2px solid #333;
}
The property box-sizing: border-box makes the browser include padding and border inside the declared 300px width, so the rendered box is exactly 300px wide instead of 300px plus padding plus border.
Marking criteria: 1 mark for the correct property/value, 1 mark for correct placement in the rule, 1 mark for explaining the effect on the rendered width.
core4 marksA card layout uses `display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;`. Explain what happens to the number of columns as the viewport width changes from 1200px to 400px, and why no media query is needed for this behaviour.Show worked solution →
At 1200px, the grid fits as many 250px-minimum columns as will fully fit (four columns of roughly 287px each after accounting for the 1rem gaps), each stretched with 1fr to share the remaining space evenly.
As the viewport narrows, auto-fit recalculates how many 250px-minimum columns can still fit; the column count drops (to three, then two) as space shrinks, until only one column fits at 400px, at which point cards stack vertically.
No media query is needed because auto-fit with minmax() already responds continuously to the container's width, unlike a media query which only changes rules at fixed, pre-chosen breakpoints.
Marking criteria: 1 mark for describing more columns at 1200px, 1 mark for describing the column count shrinking as width decreases, 1 mark for correctly explaining auto-fit/minmax recompute continuously, 1 mark for contrasting this with the fixed-breakpoint behaviour of a media query.
core4 marksThe stimulus below shows an HTML fragment. Identify two accessibility faults and explain the fix for each.
```html
<div onclick="submitForm()">Submit</div>
<input type="text" placeholder="Email">
```Show worked solution →
Fault 1: a <div> is used as a clickable control. A <div> is not focusable by keyboard and is not announced as a button by screen readers. Fix: use a real <button> element, e.g. <button onclick=\"submitForm()\">Submit</button>, which is keyboard-focusable and announced with its role.
Fault 2: the input has only a placeholder, no <label>. Placeholder text disappears once text is typed and is not reliably read as a label by all assistive technology. Fix: add an associated label, e.g. <label for=\"email\">Email</label><input id=\"email\" type=\"text\">.
Marking criteria: 1 mark per fault identified, 1 mark per correct fix, to a maximum of 4 marks.
core5 marksExplain, with reference to the box model, why adding `padding: 1rem` to an element with `width: 100%` and default `box-sizing` can cause it to overflow its parent container, and describe the fix.Show worked solution →
By default, box-sizing: content-box means the declared width: 100% applies only to the content area. Padding and border are added on top of that width, so the element's total rendered width becomes 100% + 2rem (padding on both sides) plus any border, which is wider than the parent container. This pushes the element outside the parent, often triggering an unwanted horizontal scrollbar.
The fix is to set box-sizing: border-box (commonly applied globally via a *, *::before, *::after { box-sizing: border-box; } reset). This makes the declared width include padding and border, so width: 100% stays exactly 100% of the parent regardless of padding.
Marking criteria: 1 mark for identifying content-box as the default, 1 mark for explaining padding/border are added outside the declared width, 1 mark for correctly describing the overflow effect, 2 marks for stating and explaining the border-box fix.
exam6 marksA school portal's article page reads perfectly on desktop but on a phone the text is tiny, the navigation links run off the right edge of the screen, and the user must pinch-zoom to read anything. Diagnose the likely causes and describe a complete fix, including HTML and CSS changes.Show worked solution →
Diagnosis. Text appearing tiny and requiring pinch-zoom on a phone is the classic symptom of a missing viewport meta tag: without it, mobile browsers assume a desktop-width layout (commonly 980px) and scale the whole page down to fit the phone's screen, shrinking text and controls together. Navigation links running off the screen suggest the nav is laid out with fixed pixel widths or without wrapping, and there is no responsive rule to stack or shrink it on narrow viewports.
Fix 1: add the viewport meta tag to the document head:
<meta name="viewport" content="width=device-width, initial-scale=1">
This tells the phone to render the page at its actual CSS pixel width (e.g. 390px) instead of a scaled-down desktop layout, so real font sizes are used.
Fix 2: make the navigation responsive. Lay the nav out with Flexbox and let it wrap, and add a media query to stack links vertically below a chosen breakpoint:
nav { display: flex; gap: 1rem; flex-wrap: wrap; }
@media (max-width: 600px) {
nav { flex-direction: column; gap: 0.5rem; }
}
Fix 3: use relative units for text and spacing (rem for font sizes, %/max-width for containers) so type scales with the user's base font size rather than staying a fixed pixel value that only "works" at one width.
Verification. After the fix, the page should render at native size on a 390px-wide phone with the nav links either wrapping onto a new line or stacking in a single column, and no horizontal scrollbar or pinch-zoom should be needed.
Marking criteria: 2 marks for correctly diagnosing the missing viewport meta tag as the cause of the tiny/zoomed text, 1 mark for diagnosing the nav's lack of responsive rules, 2 marks for a complete, working fix (viewport tag plus a responsive nav rule), 1 mark for justifying the fix with the underlying mechanism (device-width rendering vs desktop-width scaling).