Web Design Study Guide
HTML · CSS · JavaScript · Responsive Design · Accessibility
Prepared for: Bob
Location: New Braunfels, TX
Tools: VS Code | Chrome/Edge DevTools | Windows 10
2026
Foundational to Intermediate Level | Binder-Ready Edition
Web Design Study Guide | Bob | New Braunfels, TX | 2026
Table of Contents
Section 1 .......... How the Web Works
1.1 Client/Server Model | 1.2 HTTP/HTTPS | 1.3 DNS | 1.4 Browsers & URLs
Section 2 .......... Your Web Design Toolkit
2.1 VS Code Setup | 2.2 Extensions | 2.3 DevTools | 2.4 File Organization
Section 3 .......... HTML Foundations
3.1 Document Structure | 3.2 HTML Boilerplate | 3.3 Elements vs Tags | 3.4 Attributes
Section 4 .......... Semantic HTML & Content Elements
4.1 Semantic Tags | 4.2 Text Elements | 4.3 Lists | 4.4 Links & Images | 4.5 Tables | 4.6 Forms
Section 5 .......... CSS Foundations
5.1 The Cascade | 5.2 Selectors | 5.3 Specificity | 5.4 Box Model | 5.5 Common Properties
Section 6 .......... CSS Layout — Flexbox
6.1 Container Properties | 6.2 Item Properties | 6.3 Annotated Examples
Section 7 .......... CSS Layout — Grid
7.1 Grid Concepts | 7.2 Container Properties | 7.3 Named Areas | 7.4 fr Unit
Section 8 .......... Responsive Web Design
8.1 Mobile-First | 8.2 Media Queries | 8.3 Responsive Images | 8.4 Responsive Typography
Section 9 .......... CSS Typography & Color
9.1 Font Stacks | 9.2 Google Fonts | 9.3 Color Formats | 9.4 Accessibility & Contrast
Section 10 ......... CSS Backgrounds, Borders & Effects
10.1 Backgrounds & Gradients | 10.2 Borders | 10.3 Shadows | 10.4 Transforms & Animations
Section 11 ......... Images & Media on the Web
11.1 File Formats | 11.2 Optimization | 11.3 Responsive Images | 11.4 Video
Section 12 ......... Web Accessibility (a11y)
12.1 POUR Principles | 12.2 ARIA | 12.3 Keyboard Navigation | 12.4 Testing Tools
Section 13 ......... JavaScript Foundations
13.1 Variables & Types | 13.2 Operators | 13.3 Arrays & Objects | 13.4 Functions & Control Flow
Section 14 ......... JavaScript & the DOM
14.1 Selecting Elements | 14.2 Manipulating the DOM | 14.3 Events & Event Delegation
Section 15 ......... JavaScript — Modern Features & Async
15.1 ES6+ Features | 15.2 Promises & Async/Await | 15.3 Fetch API | 15.4 localStorage
Section 16 ......... CSS Preprocessors & Build Tools
16.1 Sass/SCSS | 16.2 npm & Vite | 16.3 DevTools Deep Dive | 16.4 Git Basics
Section 17 ......... Putting It All Together — Project Workflow
17.1 Planning | 17.2 Build Order | 17.3 Audit | 17.4 Deployment | 17.5 Project Checklist
Appendix A ...... HTML Quick Reference Card
Appendix B ...... CSS Quick Reference Card
Appendix C ...... JavaScript Quick Reference Card
Appendix D ...... VS Code Keyboard Shortcuts (Windows)
Appendix E ...... Recommended Resources
Web Design Study Guide | Bob | New Braunfels, TX | 2026
Section 1: How the Web Works
1.1 Overview
Every time you visit a website, a complex but well-orchestrated chain of events occurs behind the scenes
in milliseconds. Understanding this process is essential for every web designer and developer — it
informs how you structure files, optimize performance, and debug problems. The web is built on a
client/server model: your browser (the client) asks for resources, and a remote computer (the server)
sends them back. This conversation happens over the HTTP (Hypertext Transfer Protocol) or its secure
version HTTPS, using the universal addressing system known as URLs.
Before your browser ever contacts a web server, it must first translate a human-readable domain name
(like [Link]) into a numeric IP address using the Domain Name System (DNS). Think of
DNS as the internet's phone book. Once the IP address is resolved, your browser establishes a
connection and requests the web page's resources — HTML, CSS, JavaScript, images — which the server
delivers. Your browser's rendering engine then assembles all those pieces into the visual page you see
on screen.
1.2 Key Concepts
The Request/Response Cycle
Every interaction with a web page is a series of requests and responses. When you type a URL and press
Enter, your browser sends an HTTP GET request to the server. The server processes this and responds
with an HTTP status code and content. Common status codes include:
● 200 OK — The request succeeded and content is returned.
● 301 Moved Permanently — The resource has a new permanent URL.
● 404 Not Found — The requested resource does not exist on the server.
● 500 Internal Server Error — Something went wrong on the server side.
HTTP vs HTTPS
HTTP (Hypertext Transfer Protocol) transmits data in plain text — anyone intercepting the traffic could
read it. HTTPS (HTTP Secure) encrypts all data using TLS (Transport Layer Security), protecting sensitive
information like passwords and credit card numbers. All modern websites should use HTTPS. Browsers
like Chrome and Edge visually flag HTTP sites as "Not Secure" in the address bar.
DNS — Domain Name System
DNS is a hierarchical, distributed database that maps human-readable domain names to IP addresses.
When you type [Link], your computer queries a DNS resolver (often your ISP or a service
like Google's [Link] or Cloudflare's [Link]). The resolver traces the hierarchy — root name servers →
top-level domain servers (.com) → authoritative name servers for [Link] — and returns the IP
address. This result is then cached for a period defined by the domain's TTL (Time To Live) to speed up
future lookups.
Browsers and Rendering Engines
A web browser is much more than a window to the internet. It contains a rendering engine that parses
HTML into a DOM (Document Object Model), parses CSS into a CSSOM (CSS Object Model), and
combines them into a render tree to paint pixels on screen. Major rendering engines include:
● Blink — Used by Chrome, Edge, Opera, and most modern browsers.
● Gecko — Used by Firefox.
● WebKit — Used by Safari on macOS and iOS.
Web Standards Bodies
● W3C (World Wide Web Consortium) — Founded by Tim Berners-Lee; defines standards for
HTML, CSS, accessibility (WCAG), and more. A community of member organizations working to
develop open web standards.
● WHATWG (Web Hypertext Application Technology Working Group) — A community of
browser vendors (Apple, Google, Mozilla, Microsoft) that maintains the living standard for
HTML. Their HTML specification is what browsers actually implement today.
● ECMA International — Maintains the ECMAScript specification, which defines the JavaScript
language standard. ECMAScript 2015 (ES6) was a landmark revision that modernized JavaScript
significantly.
● IETF (Internet Engineering Task Force) — Defines internet protocols including HTTP, TCP/IP, and
TLS.
Anatomy of a URL
[Link] |___| |
_______________| |_| |_______| |_____| |______| 1 2 3 4 5
6 1. Scheme (protocol): https 2. Domain / host: [Link] 3. Port:
443 (default for HTTPS, usually omitted) 4. Path: /blog/post 5. Query string:
?id=42 6. Fragment (anchor): #comments
Text-Based Diagram: Browser → DNS → Server → Response
┌───────────────────────────────────────────────────
──────────────────┐ │ WHAT HAPPENS WHEN YOU
PRESS ENTER │
└───────────────────────────────────────────────────
──────────────────┘ [1] You type: [Link]
[2] Browser checks cache — IP already known? Use it. Otherwise... [3] DNS
Lookup: Browser → Local DNS Resolver → Root Name Server
→ .gov TLD Server → [Link] Authoritative DNS ← IP
Address: [Link] [4] TCP Handshake + TLS Handshake: Browser
←──── Encrypted Secure Connection ────→ Server [5] HTTP GET Request:
Browser ──── GET /news HTTP/2 ────────────────→ Server [6] Server
Response: Browser ←─── 200 OK + HTML document ───────── Server
[7] Browser parses HTML → discovers linked CSS, JS, images Browser ────
GET /css/[Link] ────────────→ Server Browser ──── GET
/js/[Link] ────────────────→ Server Browser ──── GET
/images/[Link] ──────────→ Server [8] Render Pipeline: HTML →
DOM CSS → CSSOM DOM + CSSOM → Render Tree → Layout →
Paint → Display ✓
1.3 Practice Exercises
1. Trace a URL: Write out every step that occurs from the moment you type
[Link] and press Enter, until the page appears. Include DNS lookup, TCP
connection, HTTP request/response, and rendering.
2. Identify URL parts: Break the following URL into its parts and label each one:
[Link]
3. HTTP Status Codes: Open Chrome or Edge DevTools (F12), go to the Network tab, load any
website, and identify 5 different HTTP responses. Note the status code and type (HTML, CSS, JS,
image) for each.
4. Research: Find out which rendering engine your primary browser uses and look up one
rendering feature that engine implemented first before others adopted it.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 1: How the Web Works
Section 2: Your Web Design Toolkit
2.1 Overview
Having the right tools set up correctly before you write a single line of code saves hours of frustration.
As a web designer working in New Braunfels, TX with VS Code on Windows 10, you already have one of
the best free code editors in the world at your fingertips. VS Code (Visual Studio Code) is a lightweight,
extensible editor developed by Microsoft that has become the dominant tool for web development
globally. In this section, you will configure your development environment, learn the essential
extensions that accelerate your workflow, master the browser's built-in developer tools, and establish
organized file structures that will serve you on every project.
2.2 VS Code Setup
VS Code is available free at [Link]. After installation, spend a few minutes configuring
these settings via File → Preferences → Settings (or Ctrl+,):
● Editor: Format On Save — Set to true so Prettier auto-formats every time you save.
● Editor: Tab Size — Set to 2 for HTML/CSS/JS (industry standard).
● Editor: Word Wrap — Set to on to avoid horizontal scrolling in long CSS files.
● Files: Auto Save — Set to afterDelay with a 1000ms delay for automatic saving.
● Editor: Font Family — Consider Cascadia Code, Consolas, 'Courier New' for a coding-
optimized monospace font.
● Editor: Font Ligatures — Set to true if using Cascadia Code for ligature arrows (==>, <=).
2.3 Essential VS Code Extensions
Extension Publisher What It Does Why You Need It
Live Server Ritwick Dey Launches a local dev See changes in browser
server with live reload instantly on every save
Prettier Prettier Opinionated code Consistent indentation
formatter for HTML, CSS, and style automatically
JS
HTMLHint HTMLHint Lints your HTML for Catches unclosed tags,
common errors duplicate IDs, missing alt
text
Extension Publisher What It Does Why You Need It
CSS Peek Pranay Prakash Peek/jump to CSS class Navigate large
definitions from HTML stylesheets without
switching files
Bracket Pair Colorizer CoenraadS Colors matching Instantly spot
brackets, braces, and unmatched brackets in
parentheses complex JS
GitLens GitKraken Supercharges Git See who wrote each line
integration with inline and why — invaluable in
blame, history teams
IntelliSense for CSS Zignd Autocompletes CSS class Stop guessing class
names from HTML names; autocomplete
them from your
stylesheet
Auto Rename Tag Jun Han Auto-renames paired Rename opening tag and
HTML/XML tags closing tag updates
simultaneously
💡 TIP: Installing Extensions
Open the Extensions panel with Ctrl+Shift+X. Type the extension name, click Install. After installing
Live Server, right-click your [Link] file in the Explorer panel and choose "Open with Live
Server". Your default browser will open at [Link]
2.4 Folder Structure & Naming Conventions
Consistent file organization is a professional habit that prevents headaches on larger projects. Here is
the recommended structure for a beginner-to-intermediate project:
my-project/ │ ├── [Link] ← Homepage (always named [Link]) ├──
[Link] ← Additional pages at root level ├── [Link] │ ├── css/ │
├── [Link] ← Main stylesheet │ └── [Link] ← CSS reset
(optional) │ ├── js/ │ ├── [Link] ← Main JavaScript file │ └── [Link]
← Helper functions (optional) │ ├── images/ │ ├── [Link] ← Optimized
web images │ ├── [Link] ← Vector graphics │ └── icons/ ← Icon
assets subfolder │ └── fonts/ ← Self-hosted web fonts (optional) └──
custom-font.woff2
Naming Conventions:
● Use all lowercase for all file and folder names.
● Use hyphens (not underscores or spaces) to separate words: [Link], hero-
[Link].
● Never use spaces, special characters, or capital letters in file names — servers are case-sensitive
and spaces cause URL encoding issues.
● Name the homepage [Link] — this is the default file servers look for in any directory.
● Use descriptive names: [Link] is better than [Link].
2.5 Browser Developer Tools
The browser DevTools are your most powerful debugging instrument — and they are built right into
your browser, free. In Chrome or Edge, press F12 or Ctrl+Shift+I to open them.
Panel What You Can Do
Elements Inspect and live-edit HTML and CSS. Hover over
elements to highlight them on the page. The
Computed tab shows final resolved styles.
Console Run JavaScript, see errors and warnings, use
[Link]() for debugging.
Network Monitor every HTTP request, response code, file size,
and load time. Filter by type: HTML, CSS, JS, Image,
Fetch.
Sources Browse source files, set breakpoints, and step
through JavaScript execution.
Performance Record page load and interaction, identify slow
rendering and JavaScript bottlenecks.
Panel What You Can Do
Lighthouse Run automated audits for Performance, Accessibility,
SEO, and Best Practices. Returns a score out of 100 for
each.
Device Toolbar Simulate different screen sizes and devices. Press
Ctrl+Shift+M to toggle.
2.6 VS Code Keyboard Shortcuts (Quick Reference)
Shortcut Action
Ctrl+/ Toggle line comment
Ctrl+P Quick Open — search and open any file in project
Alt+Shift+F Format document (runs Prettier)
Ctrl+` Toggle integrated terminal
Ctrl+Shift+P Command Palette — access all VS Code commands
Alt+↑ / Alt+↓ Move current line up or down
Ctrl+D Select next occurrence of current word
Ctrl+Shift+K Delete current line
Ctrl+Z Undo
Ctrl+Shift+Z Redo
2.7 Quick Reference Checklist
● VS Code installed and updated to latest version
● Live Server extension installed and working
● Prettier installed and "Format On Save" enabled
● HTMLHint and CSS Peek extensions installed
● Project folder structure matches recommended layout above
● All file names are lowercase with hyphens, no spaces
● Homepage is named [Link]
● Browser DevTools tested — can open and inspect any element
● Live Server tested — changes in VS Code appear live in browser
2.8 Practice Exercises
5. Setup: Create a new project folder called my-first-site with the folder structure
shown in section 2.4. Create an empty [Link], css/[Link], and js/[Link].
Open the folder in VS Code using File → Open Folder.
6. Extensions: Install all six extensions listed in the table above. Verify Live Server
works by adding some text to [Link], right-clicking, and opening with Live
Server.
7. DevTools: Open Chrome or Edge, navigate to any website (try
[Link] press F12, and perform these tasks:
○ Inspect the navigation bar element and read its CSS class names.
○ Change the color of a heading using the Elements panel (this does not
save — it is temporary).
○ Open the Console tab and type [Link] and press Enter. What
does it return?
○ Open the Network tab, reload the page, and find the main HTML file. What
is its response status code?
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 2: Your Web Design Toolkit
Section 3: HTML Foundations
3.1 Overview
HTML (HyperText Markup Language) is the foundational language of the web. It provides the structure
and content of every web page — it is the skeleton that CSS dresses up and JavaScript brings to life.
HTML uses elements made up of opening and closing tags to describe the meaning and organization of
content. It was first proposed by Tim Berners-Lee in 1989 and has evolved through many versions; the
current standard is HTML5, maintained as a living standard by the WHATWG.
A critical mindset shift for beginners: HTML is about meaning, not appearance. When you write HTML,
you are describing what content is (a heading, a paragraph, a list, a navigation menu), not how it looks.
Appearance is CSS's responsibility. This separation of concerns is a core principle of modern web
development.
3.2 Elements, Tags, and Attributes
Elements vs Tags
An element includes everything from the opening tag to the closing tag, including the content in
between. A tag is just the markup indicator surrounded by angle brackets.
<!-- Tag = just the markup indicator --> <h1> <!--
Opening tag --> </h1> <!-- Closing tag --> <!-- Element =
opening tag + content + closing tag --> <h1>Welcome to My Website</h1>
Void Elements (Self-Closing)
Some elements have no content and do not require a closing tag. These are called void elements:
<img src="[Link]" alt="A sunset photo"> <br> <!-- Line break -->
<hr> <!-- Horizontal rule --> <input type="text"> <meta charset="UTF-
8"> <link rel="stylesheet" href="css/[Link]">
⚠️NOTE: Self-Closing Slash
In HTML5, the trailing slash in void elements (<br />) is optional and has no effect. It was required
in XHTML but is unnecessary in modern HTML5. Both <br> and <br /> are valid. Consistency is
what matters — pick one style and stick with it.
Attributes
Attributes provide additional information about an element. They are always placed in the opening tag
and follow the format name="value":
<a href="[Link] target="_blank" rel="noopener"> Visit
Example </a> <!-- href = the URL the link points to --> <!-- target = where
to open the link (_blank = new tab) --> <!-- rel = relationship; noopener
is a security best practice -->
Block vs Inline Elements
Block Elements Inline Elements
Start on a new line; take full width available Flow within text; only take up as much space as
needed
Can contain block and inline elements Can only contain inline elements and text
div, p, h1-h6, ul, ol, li, section, span, a, strong, em, img, code, br,
article, header, footer, main, aside, input, label, button, abbr, cite
nav, blockquote, table, form
3.3 The HTML Boilerplate — Fully Annotated
Every HTML page you build should start with this structure. This is called the HTML boilerplate:
<!DOCTYPE html> <!-- Declares this is an HTML5 document. Must be the very
first line. Without it, browsers enter "Quirks Mode" and render
inconsistently. --> <html lang="en"> <!-- The root element wrapping all page
content. lang="en" tells browsers and screen readers the page language.
Change to lang="es" for Spanish, lang="fr" for French, etc. Required for
accessibility and SEO. --> <head> <!-- The head contains metadata —
information ABOUT the page, not content displayed to the user. -->
<meta charset="UTF-8"> <!-- Specifies character encoding. UTF-8 supports
every character in every human language. Always the first meta tag in
head. --> <meta name="viewport" content="width=device-width, initial-
scale=1.0"> <!-- CRITICAL for responsive design. Without this, mobile
browsers render pages at a desktop width (~980px) and zoom out.
width=device-width: sets viewport to device screen width. initial-
scale=1.0: sets initial zoom level to 100%. --> <title>Page Title — My
Website</title> <!-- Shown in browser tab and in search engine results.
Should be descriptive and unique per page (50-60 characters ideal).
Format: "Page Name — Site Name" --> <meta name="description" content="A
brief description of this page."> <!-- Summary shown in search engine
results (150-160 chars). Does not affect ranking directly, but improves
click-through rates. --> <link rel="stylesheet" href="css/[Link]">
<!-- Links an external CSS file to this page. rel="stylesheet" tells
browser this is a stylesheet. href is the path to the CSS file —
relative to this HTML file. Place ABOVE any JavaScript links to avoid
render-blocking. --> </head> <body> <!-- All visible content goes inside the
body element. Only one <body> element is allowed per page. --> <!--
Page content goes here --> <script src="js/[Link]" defer></script> <!--
Links an external JavaScript file. defer: tells browser to download JS
file in background, but only execute it AFTER the HTML is fully parsed.
This prevents JS from blocking page rendering. Recommended placement:
end of head with defer, OR at bottom of body (older approach). -->
</body> </html> <!-- Closing html tag ends the document -->
3.4 Nesting Rules
Elements must be properly nested — closed in the reverse order they were opened. Think of them like
nested boxes: you must close the inner box before closing the outer box.
<!-- CORRECT nesting --> <p>This is <strong>very important</strong>
information.</p> <!-- WRONG nesting (will cause rendering errors) --> <p>This
is <strong>very important</p></strong> <!-- CORRECT: ul contains li elements
--> <ul> <li>Item one</li> <li>Item two</li> </ul> <!-- WRONG: inline
element cannot contain block element --> <span><div>This is
invalid!</div></span>
3.5 Quick Reference Checklist
● Document begins with <!DOCTYPE html> on the very first line
● <html lang="en"> has the correct language code
● <meta charset="UTF-8"> is first tag inside <head>
● Viewport meta tag is present for responsive design
● <title> is descriptive, unique, and 50-60 characters
● External stylesheet linked with <link rel="stylesheet">
● Script tag uses defer attribute
● All elements properly nested — no overlapping tags
● Void elements have no closing tag
3.6 Practice Exercises
8. From Scratch: Without looking at the boilerplate above, type out a complete HTML5 boilerplate
from memory. Then compare to the annotated version. Which parts did you miss?
9. Hobby Page: Build an HTML-only page (no CSS yet) about one of your hobbies. Include: a page
title in the tab, an h1 heading, three paragraphs of content, an unordered list of related items,
and at least one link to an external website. Validate your HTML using the W3C Validator at
[Link].
10. Recipe: Mark up a simple recipe using proper semantic tags. Use <h1> for the recipe name,
<h2> for "Ingredients" and "Instructions", <ul> for ingredients, and <ol> for numbered steps.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 3: HTML Foundations
Section 4: Semantic HTML & Content Elements
4.1 Overview
Semantic HTML means using HTML elements that convey the meaning of the content they contain, not
just its visual appearance. Before HTML5, developers built page layouts almost entirely out of <div>
and <span> elements, relying on class names for any sense of meaning. HTML5 introduced a rich set of
semantic structural elements that make your code more readable, your pages more accessible to
assistive technologies, and your content more understandable to search engines.
When a screen reader encounters a <nav> element, it announces "navigation" to the user. When
Google's crawler sees <article>, it understands that content is a self-contained piece of writing. This
combination of better accessibility (a11y) and better SEO makes semantic HTML a professional
requirement, not just a nice-to-have.
4.2 HTML5 Structural / Semantic Elements
Element Purpose Notes
<header> Introductory content or navigation Can appear multiple times (e.g., in
for a section or page each <article>)
<nav> Major navigation block of links Not every group of links — only
primary/secondary navigation
<main> The dominant content of the page Only ONE <main> per page; skip-
body to-main links target this
<article> Self-contained, independently Blog post, news article, forum
distributable content post, product card
<section> Thematic grouping of content, Use when content belongs
typically with a heading together but is not independently
distributable
<aside> Content tangentially related to Sidebars, pull quotes, related
Element Purpose Notes
main content articles, advertising
<footer> Footer for its nearest sectioning Copyright, contact, navigation
ancestor links, author info
<figure> Self-contained content with Images, diagrams, code blocks,
optional caption charts
<figcaption> Caption for a <figure> element Goes as first or last child of
<figure>
<time> A specific time or date Use datetime attribute for
machine-readable format
<address> Contact information for the Not for postal addresses in general
nearest ancestor — for contact info related to
content
<mark> Highlighted / marked text Search result highlights, relevant
portions in a quote
<details> Disclosure widget — shows/hides Native accordion without
content JavaScript
<summary> Visible label/toggle for a Must be the first child of
<details> element <details>
<!-- Example: Semantic page structure --> <body> <header> <a href="/"
class="logo">My Site</a> <nav> <ul> <li><a
href="/">Home</a></li> <li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li> </ul> </nav> </header>
<main> <article> <header> <h1>Blog Post Title</h1>
<p>By Bob <time datetime="2026-06-24">June 24, 2026</time></p> </header>
<section> <h2>Introduction</h2> <p>Content here...</p>
</section> <figure> <img src="images/[Link]"
alt="Architecture diagram"> <figcaption>Figure 1: System architecture
overview.</figcaption> </figure> </article> <aside>
<h2>Related Articles</h2> <ul>...</ul> </aside> </main>
<footer> <p>© 2026 Bob | New Braunfels, TX</p> <address>Contact:
<a href="[Link] </footer>
</body>
4.3 Heading Hierarchy
Headings (h1 through h6) create an outline of your document. They are critically important for
accessibility — screen reader users often navigate pages by jumping between headings. Rules to follow:
● Only one <h1> per page — it represents the main topic of the entire page.
● Never skip heading levels — do not jump from <h2> to <h4>.
● Headings convey structure, not style — never pick a heading level because of its default size.
Use CSS to style them.
● <h2> headings are major subsections; <h3> are subsections of those; and so on.
4.4 Text Content Elements
Element Meaning Renders As (default)
<p> Paragraph of text Block with space above/below
<strong> Strong importance (semantically Bold
important)
<em> Emphasis (stress emphasis) Italic
<blockquote> Long quotation from external Indented block
source
<cite> Title of a creative work cited Italic
<q> Short inline quotation Wrapped in quotation marks
<pre> Preformatted text (whitespace Monospace, preserves
preserved) spaces/newlines
<code> Inline code or computer output Monospace
<kbd> Keyboard input Monospace
<samp> Sample output from a program Monospace
<abbr> Abbreviation or acronym Dotted underline; title attr for
expansion
<dfn> Term being defined Italic
<small> Side comments, fine print Smaller font
<sub> / <sup> Subscript / Superscript Below/above baseline, smaller
<del> / <ins> Deleted / Inserted text (document Strikethrough / Underline
edits)
<br> Line break (within content) New line
<hr> Thematic break between content Horizontal line
4.5 Lists
<!-- Unordered List: items without inherent order --> <ul> <li>HTML</li>
<li>CSS</li> <li>JavaScript</li> </ul> <!-- Ordered List: items with a
sequence --> <ol> <li>Plan the layout</li> <li>Write the HTML
structure</li> <li>Apply CSS styles</li> <li>Add JavaScript behavior</li>
</ol> <!-- Definition List: terms and their definitions --> <dl>
<dt>HTML</dt> <dd>HyperText Markup Language — the structure of web
pages</dd> <dt>CSS</dt> <dd>Cascading Style Sheets — the presentation of
web pages</dd> </dl>
When to use each:
● <ul> — Items where order does not matter (ingredients, features, navigation links).
● <ol> — Items where order matters (steps in a process, rankings, numbered instructions).
● <dl> — Key-value pairs (glossaries, metadata, FAQ questions and answers).
4.6 Links
<!-- Absolute URL (external link) --> <a href="[Link]
target="_blank" rel="noopener noreferrer"> MDN Web Docs </a> <!--
target="_blank" opens in new tab --> <!-- rel="noopener noreferrer" is a
security best practice for external links --> <!-- Relative URL (internal
link — same site) --> <a href="/[Link]">About Page</a> <a
href="[Link]">About Page (relative to current file)</a> <a
href="../images/[Link]">../ goes up one folder</a> <!-- Email link --> <a
href="[Link] me an email</a> <!-- Phone link --> <a
href="[Link] 300-0000</a> <!-- Anchor link (same page) -->
<a href="#section-2">Jump to Section 2</a> <h2 id="section-2">Section 2:
Toolkit</h2>
4.7 Images
<!-- Basic image -- alt text is REQUIRED for accessibility --> <img
src="images/[Link]" alt="Sunset over the Guadalupe River in New
Braunfels, TX" width="800" height="450" loading="lazy"
decoding="async"> <!-- Always include width and height attributes --> <!--
They prevent Cumulative Layout Shift (CLS) during loading --> <!--
loading="lazy" defers off-screen image loading for performance --> <!--
decoding="async" lets browser decode image without blocking rendering -->
<!-- Image with caption using figure --> <figure> <img src="images/comal-
[Link]" alt="Tubers on the Comal River on a sunny day"
width="600" height="400" loading="lazy"> <figcaption>The Comal River is the
shortest river in the United States.</figcaption> </figure>
⚠️NOTE: Alt Text Rules
The alt attribute is not optional. Without it, screen readers announce the file name — meaningless
to visually impaired users. Write descriptive alt text that conveys the purpose of the image. For
purely decorative images, use alt="" (empty string) — this tells screen readers to skip the image
entirely. Never use "image of" or "photo of" as a prefix — screen readers already announce it as an
image.
4.8 Tables
<table> <caption>Web Browser Market Share (2026)</caption> <!-- caption is
optional but improves accessibility --> <thead> <tr> <th
scope="col">Browser</th> <th scope="col">Engine</th> <th
scope="col">Market Share</th> </tr> </thead> <tbody> <tr>
<td>Chrome</td> <td>Blink</td> <td>65%</td> </tr> <tr>
<td>Safari</td> <td>WebKit</td> <td>19%</td> </tr> </tbody>
<tfoot> <tr> <td colspan="2">Total tracked browsers</td>
<td>100%</td> </tr> </tfoot> </table>
⚠️NOTE: Never Use Tables for Layout
Tables are for tabular data — information that has a meaningful relationship between rows and
columns. Never use <table> elements to control page layout. That was a 1990s technique. Use
CSS Flexbox and Grid (Sections 6 and 7) for layout instead. Using tables for layout breaks
accessibility and is extremely difficult to make responsive.
4.9 Forms — Complete Guide
<form action="/submit" method="POST" novalidate> <!-- action: where form
data is sent (URL) --> <!-- method: GET (data in URL) or POST (data in body,
more secure) --> <!-- novalidate: disable browser default validation (use
custom JS) --> <fieldset> <legend>Personal Information</legend>
<!-- fieldset groups related fields; legend labels the group --> <label
for="full-name">Full Name <span aria-hidden="true">*</span></label> <input
type="text" id="full-name" name="fullName"
placeholder="Jane Smith" required autocomplete="name">
<!-- for= must match id= to associate label with input --> <!-- name= is
sent to the server --> <!-- required prevents submission if empty -->
<label for="email">Email Address</label> <input type="email" id="email"
name="email" placeholder="jane@[Link]" required
autocomplete="email"> <label for="password">Password</label> <input
type="password" id="password" name="password" minlength="8"
required autocomplete="new-password"> <label for="birthdate">Date of
Birth</label> <input type="date" id="birthdate" name="birthdate">
<label for="volume">Volume: <span id="vol-output">50</span></label> <input
type="range" id="volume" name="volume" min="0" max="100"
value="50"> <label for="favorite-color">Favorite Color</label> <input
type="color" id="favorite-color" name="favoriteColor"> </fieldset>
<fieldset> <legend>Preferences</legend> <!-- Radio buttons (one
choice from group) --> <p>Preferred contact method:</p> <label><input
type="radio" name="contact" value="email"> Email</label> <label><input
type="radio" name="contact" value="phone"> Phone</label> <!-- Radio
buttons sharing the same name= form a group --> <!-- Checkboxes (multiple
choices) --> <p>Interests (select all that apply):</p> <label><input
type="checkbox" name="interests" value="html"> HTML</label> <label><input
type="checkbox" name="interests" value="css"> CSS</label> <label><input
type="checkbox" name="interests" value="js"> JavaScript</label> <!--
Select dropdown --> <label for="state">State</label> <select
id="state" name="state"> <option value="">-- Select a state --</option>
<option value="TX" selected>Texas</option> <option
value="CA">California</option> </select> <!-- Textarea (multi-line
text input) --> <label for="message">Message</label> <textarea
id="message" name="message" rows="5" cols="40"
placeholder="Type your message here..."></textarea> </fieldset> <button
type="submit">Submit Form</button> <button type="reset">Reset All
Fields</button> </form>
4.10 Quick Reference Checklist
● All images have meaningful alt text (or alt="" for decorative)
● Every form input has an associated <label> (via for/id)
● Headings are in order: h1 → h2 → h3 (no skipped levels)
● Only one <h1> per page
● Lists used correctly (ul for unordered, ol for numbered steps)
● Tables used only for tabular data, never for layout
● All tables have <thead>, <tbody>, and scope on <th>
● Page uses semantic structure: header, nav, main, footer
● External links use rel="noopener noreferrer"
● Images include width, height, and loading="lazy"
4.11 Practice Exercises
11. Semantic Layout: Mark up a full webpage layout for a fictional restaurant called "Oma's
Kitchen" in New Braunfels, TX. Use <header>, <nav>, <main>, <section>, <article>,
<aside>, and <footer> appropriately. Include a menu as a table.
12. Contact Form: Build a complete contact form with: name, email, phone (tel input), a dropdown
for inquiry type, a textarea for the message, a checkbox for newsletter opt-in, and a submit
button. All inputs must have labels.
13. Data Table: Create an HTML table showing a comparison of 5 programming languages with
columns: Language, Year Created, Primary Use, Typing. Add a <caption>, proper
<thead>/<tbody>, and scope attributes.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 4: Semantic HTML & Content Elements
Section 5: CSS Foundations
5.1 Overview
CSS (Cascading Style Sheets) controls the visual presentation of HTML. While HTML defines what
content is, CSS defines how it looks — colors, fonts, spacing, layout, animations, and more. The word
"Cascading" describes how CSS resolves conflicts when multiple style rules apply to the same element: it
uses a specific algorithm based on specificity, importance, and source order to determine which rule
wins.
CSS connects to HTML in three ways (in order of preference): external stylesheets (a separate .css file
linked with <link>), internal styles (a <style> block in the <head>), and inline styles (a style
attribute on an element). Always prefer external stylesheets — they keep presentation separate from
structure and allow one CSS file to style an entire multi-page website.
5.2 CSS Syntax
/* CSS Syntax: selector { property: value; } */ h1 { /*
Selector: targets all h1 elements */ color: #2563eb; /* Property:
color; Value: hex blue */ font-size: 32pt; /* Properties end with
semicolons */ margin-bottom: 16pt; /* Multiple declarations allowed */ }
/* Class selector (most common): targets elements with class="btn" */ .btn {
background-color: #2563eb; color: #ffffff; padding: 10px 20px; } /* ID
selector: targets element with id="main-title" */ #main-title { text-align:
center; } /* Comments in CSS use /* */ syntax, not // */
5.3 Selectors — Complete Reference
Selector Type Syntax Targets
Element p { } All <p> elements
Class .card { } All elements with class="card"
ID #header { } Element with id="header"
(unique per page)
Universal * { } Every element on the page
Attribute input[type="email"] { } Inputs with type="email"
Pseudo-class a:hover { } Links being hovered over
Pseudo-class li:first-child { } First <li> in a list
Pseudo-class li:nth-child(2n) { } Every even <li>
Pseudo-element p::first-line { } First line of every paragraph
Pseudo-element .card::before { } Inserts generated content
before .card
Descendant nav a { } All <a> anywhere inside <nav>
Child ul > li { } Direct <li> children of <ul> only
Adjacent sibling h2 + p { } First <p> immediately after <h2>
General sibling h2 ~ p { } All <p> siblings after <h2>
Grouping h1, h2, h3 { } All headings at once (comma-
separated)
5.4 The Cascade: How CSS Resolves Conflicts
When multiple rules target the same element, CSS uses a three-step algorithm:
14. Importance: Rules with !important override all others. (Use sparingly — it breaks the cascade
and makes debugging hard.)
15. Specificity: More specific selectors win over less specific ones. Calculated as a four-part score
(see below).
16. Source Order: If importance and specificity are equal, the rule that appears later in the CSS wins.
Specificity Scoring
Source Score Example
Inline style 1-0-0-0 style="color: red;"
ID selector 0-1-0-0 #sidebar { }
Class / pseudo-class / attribute 0-0-1-0 .nav, :hover, [type]
Element / pseudo-element 0-0-0-1 p, h1, ::before
Universal selector / combinators 0-0-0-0 *, >, +, ~
/* Specificity worked example */ p { color: black; } /*
0-0-0-1 */ .intro { color: blue; } /* 0-0-1-0 */ #main p
{ color: green; } /* 0-1-0-1 */ #main [Link] { color: red; }
/* 0-1-1-1 */ /* For a <p class="intro"> inside #main: color is RED
because 0-1-1-1 beats all others */
5.5 CSS Units
Unit Type Relative To Best Used For
px Absolute Screen pixels (device- Borders, shadows,
independent) precise fixed values
em Relative Parent element's font- Padding, margins relative
size to text size
rem Relative Root (html) element's Font sizes, spacing —
font-size consistent scaling
% Relative Parent element's value Widths, heights in fluid
layouts
vw Viewport 1% of viewport width Full-width elements,
fluid typography
vh Viewport 1% of viewport height Full-height sections:
hero, fullscreen
vmin Viewport 1% of smaller viewport Square elements that
dimension scale with viewport
ch Relative Width of the "0" Limiting paragraph width
character in current font (55-75ch ideal)
💡 TIP: rem vs em
Use rem for font sizes and most spacing — it scales from the root font size (usually 16px in
browsers) and stays consistent throughout the document. Use em when you want padding or
spacing to scale with its own element's font size (e.g., a button's padding should grow if the button's
text gets larger).
5.6 The Box Model
Every HTML element is a rectangular box. The CSS box model describes the layers of that box from
inside to outside:
┌───────────────────────────────────────────────────
───┐ │ MARGIN │ ← Transparent space outside
the border │
┌──────────────────────────────────────────────┐ │ │
│ BORDER │ │ ← The visible edge (color, style, width)
│ │ ┌──────────────────────────────────────┐ │ │ │ │
│ PADDING │ │ │ ← Space between content and border │
│ │ ┌──────────────────────────────┐ │ │ │ │ │ │ │
CONTENT │ │ │ │ ← Text, images, children │ │ │ │ width ×
height applies │ │ │ │ │ │ │
└──────────────────────────────┘ │ │ │ │ │
└──────────────────────────────────────┘ │ │ │
└──────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────
───┘
/* box-sizing: border-box — THE most important CSS reset */ /* Without it:
width = content only (padding and border ADD to total width) */ /* With it:
width = content + padding + border (predictable!) */ *, *::before, *::after {
box-sizing: border-box; /* Apply to EVERYTHING using universal selector */ }
/* Example: */ .box { width: 300px; padding: 20px; border: 2px solid
#000; } /* Without border-box: actual width = 300 + 40 (padding) + 4 (border)
= 344px */ /* With border-box: actual width = exactly 300px (padding/border
included) */
5.7 Common CSS Properties
/* Typography */ .text-example { font-family: 'Segoe UI', system-ui, sans-
serif; /* Font stack: fallbacks */ font-size: 1rem; /* 1rem = 16px
at default browser settings */ font-weight: 600; /* 100-900;
400=normal, 700=bold */ font-style: italic; /* normal | italic |
oblique */ line-height: 1.6; /* Unitless: 1.6x the font-size.
Recommended: 1.4-1.6 */ letter-spacing: 0.02em; /* Space between
characters */ text-align: left; /* left | center | right | justify
(avoid justify) */ text-decoration: none; /* none | underline | line-
through */ text-transform: uppercase; /* none | uppercase | lowercase |
capitalize */ color: #1a1a1a; } /* Spacing */ .spacing-example { margin:
16px; /* All four sides */ margin: 16px 24px; /*
Top/bottom: 16px; Left/right: 24px */ margin: 8px 12px 16px 20px; /* Top
Right Bottom Left (clockwise) */ margin: 0 auto; /* Horizontally
center a block element */ padding: 20px 32px; /* Inside spacing
*/ } /* Borders */ .border-example { border: 2px solid #2563eb; /*
Width style color shorthand */ border-top: 4px solid #2563eb; /*
Individual sides */ border-radius: 8px; /* Rounded corners */
outline: 2px solid #ff6600; /* Outside the border (doesn't affect layout)
*/ } /* Dimensions */ .size-example { width: 100%; /* 100% of
parent */ max-width: 1200px; /* Never wider than 1200px */ min-width:
320px; /* Never narrower than 320px */ height: auto; /* Grows
with content */ min-height: 100vh; /* At least full viewport height */ }
/* Display */ .display-example { display: block; /* Block-level */
display: inline; /* Inline */ display: inline-block; /* Inline but
respects width/height */ display: none; /* Hidden AND removed from
layout */ visibility: hidden; /* Hidden but still takes up space */ } /*
Other visual */ .visual-example { opacity: 0.8; /* 0 = fully
transparent, 1 = fully opaque */ overflow: hidden; /* visible | hidden
| scroll | auto */ cursor: pointer; /* Changes cursor to hand (useful
for buttons) */ }
5.8 CSS Custom Properties (Variables)
/* Define variables in :root so they're available everywhere */ :root { --
primary-color: #2563eb; --primary-dark: #1d4ed8; --text-dark:
#1a1a1a; --text-light: #6b7280; --spacing-sm: 0.5rem; --spacing-
md: 1rem; --spacing-lg: 2rem; --font-body: 'Segoe UI', system-
ui, sans-serif; --border-radius: 8px; } /* Use variables with var()
function */ .button { background-color: var(--primary-color); color:
#ffffff; padding: var(--spacing-sm) var(--spacing-md); border-radius:
var(--border-radius); font-family: var(--font-body); } .button:hover
{ background-color: var(--primary-dark); /* Easy to maintain! */ }
5.9 Quick Reference Checklist
● External stylesheet linked from HTML (not inline styles)
● *, *::before, *::after { box-sizing: border-box; } at top of CSS
● CSS custom properties defined in :root for colors and spacing
● Font sizes use rem for consistency
● No !important (unless overriding third-party styles)
● CSS organized logically: reset → base → typography → layout → components
● Class selectors preferred over ID selectors for reusability
● Specificity is intentional — no overly complex selectors
5.10 Practice Exercises
17. Specificity Calculator: For each selector below, calculate the specificity score:
○ nav ul li a:hover
○ #sidebar .widget h3
○ .[Link]::before
○ body > header nav a
○ *
18. Box Model: Create a <div> with a width of 400px, 30px padding, a 3px border,
and 20px margin. First calculate the total space it takes up WITHOUT box-sizing:
border-box, then WITH it. Add the CSS, apply it to your page, and use DevTools
to verify.
19. CSS Refactor: Take the HTML hobby page from Section 3 and style it with an
external stylesheet. Use element selectors first, then refactor to use class
selectors. Define at least 4 CSS variables in :root.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 5: CSS Foundations
Section 6: CSS Layout — Flexbox
6.1 Overview
Flexbox (Flexible Box Layout) is a one-dimensional CSS layout system designed to distribute space along
a single axis — either horizontally (a row) or vertically (a column). It excels at aligning items, distributing
space between them, and creating flexible, responsive component-level layouts. Before Flexbox,
centering an element vertically required hacky CSS tricks. Now it is a single property: align-items:
center.
Flexbox works on a parent/child relationship. The element you apply display: flex to becomes the
flex container, and its direct children become flex items. Properties on the container control the overall
layout direction and spacing. Properties on the items control their individual size and alignment within
the container.
💡 TIP: Flexbox vs Grid
Use Flexbox for one-dimensional layouts — a navigation bar (horizontal row), a row of buttons, a
column of form elements. Use CSS Grid (Section 7) for two-dimensional layouts — page structure
with rows AND columns simultaneously, like a full-page layout or a card grid.
6.2 Flex Container Properties
Property Values Description
display flex | inline-flex Activates flex layout on the
container
flex-direction row | row-reverse | column Sets the main axis direction
| column-reverse
justify-content flex-start | flex-end | Aligns items along the main axis
center | space-between |
space-around | space-
evenly
align-items flex-start | flex-end | Aligns items along the cross axis
center | stretch | (single row)
baseline
align-content flex-start | flex-end | Aligns multiple rows along the
center | space-between | cross axis
space-around | stretch
flex-wrap nowrap | wrap | wrap- Controls whether items wrap to a
reverse new line
Property Values Description
gap e.g., 1rem or 1rem 2rem Space between flex items (row-
gap column-gap)
6.3 Flex Item Properties
Property Values Description
flex-grow 0 (default) or positive number How much an item grows to fill
available space
flex-shrink 1 (default) or positive number How much an item shrinks when
space is tight
flex-basis e.g., auto | 250px | 30% The item's ideal size before
growing/shrinking
flex Shorthand: grow shrink basis flex: 1 1 auto; is common;
flex: 1 = 1 1 0
align-self auto | flex-start | flex- Overrides align-items for a single
end | center | stretch item
order Integer (default: 0) Visual order of item (lower =
earlier). Does not affect DOM
order.
6.4 Annotated Flexbox Examples
/* === EXAMPLE 1: Perfectly Centered Content (Hero Section) === */ .hero
{ display: flex; justify-content: center; /* Center horizontally along
main axis (row) */ align-items: center; /* Center vertically along
cross axis */ min-height: 100vh; /* Full viewport height */ text-
align: center; /* Center the text within the flex item */ } /* ===
EXAMPLE 2: Navigation Bar === */ .navbar { display: flex; justify-content:
space-between; /* Logo on left, links on right */ align-items: center;
/* Vertically centered */ padding: 1rem 2rem; /* Top/bottom
1rem, left/right 2rem */ background-color: #1e3a8a; } .navbar .logo
{ font-size: 1.5rem; font-weight: bold; color: #ffffff; } .navbar ul {
display: flex; /* The nav list is ALSO a flex container */ gap: 2rem;
/* Space between nav links */ list-style: none; /* Remove bullet points */
margin: 0; padding: 0; } /* === EXAMPLE 3: Responsive Card Row with
Wrapping === */ .cards-container { display: flex; flex-wrap: wrap; /*
Items wrap to new lines when no space */ gap: 1.5rem; /* Gap between
cards in both directions */ } .card { flex: 1 1 280px; /* grow:1
shrink:1 basis:280px Items grow to fill row, but base
size is 280px When viewport is too narrow, they wrap
to next line */ background-color: #ffffff; border: 1px solid #e5e7eb;
padding: 1.5rem; border-radius: 8px; } /* === EXAMPLE 4: Sidebar Layout ===
*/ .page-layout { display: flex; gap: 2rem; align-items: flex-start; /*
Sidebar and main don't stretch to equal height */ } .sidebar { flex: 0 0
250px; /* grow:0 shrink:0 basis:250px = fixed 250px width */ } .main-content
{ flex: 1; /* Takes all remaining space */ }
💡 TIP: Visualizing the Axes
With flex-direction: row (default): the main axis runs left to right. justify-content
controls horizontal alignment. align-items controls vertical alignment. With flex-direction:
column, the axes swap — justify-content controls vertical alignment and align-items
controls horizontal alignment.
6.5 Quick Reference Checklist
● Use gap instead of margins between flex children
● Apply flex-wrap: wrap for responsive rows that should reflow
● Use Flexbox for component-level, one-dimensional layouts
● Use CSS Grid (Section 7) for two-dimensional page layouts
● Do not apply flex properties to the flex container's children's children
● align-items for cross-axis alignment; justify-content for main axis
● Use flex: 1 as shorthand for equal-width growing items
● Test flex layouts at multiple viewport widths using DevTools device emulator
6.6 Practice Exercises
20. Centered Hero: Build a hero section that is 100vh tall with a heading and button centered both
horizontally and vertically using Flexbox. Add a background color or gradient.
21. Responsive Navigation: Build a navigation bar with a logo on the left and five nav links on the
right. The links should be evenly spaced. On small screens (below 768px), use a media query to
change flex-direction to column to stack them vertically.
22. Card Grid: Create a card grid using flex-wrap: wrap and flex: 1 1 280px. Each card
should have a title, description, and button. Verify that cards reflow naturally as you resize the
viewport.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 6: CSS Layout — Flexbox
Section 7: CSS Layout — CSS Grid
7.1 Overview
CSS Grid Layout is a two-dimensional layout system that lets you position elements in rows and columns
simultaneously. While Flexbox handles one axis at a time, Grid handles both — making it ideal for full-
page layouts, magazine-style designs, image galleries, and any UI that requires precise placement in a
grid structure.
Grid introduces concepts like tracks (the rows and columns themselves), lines (the numbered dividers
between tracks), cells (individual intersections), areas (named regions), and the revolutionary fr unit for
fractional space distribution.
7.2 The fr Unit
The fr (fractional) unit represents a fraction of the available free space in a grid container after fixed-
size columns have been accounted for:
/* Three equal columns */ .grid { grid-template-columns: 1fr 1fr 1fr; } /*
Same as: */ .grid { grid-template-columns: repeat(3, 1fr); } /* Mixed: fixed
sidebar + flexible main */ .layout { grid-template-columns: 250px 1fr; } /*
Sidebar is exactly 250px; main takes ALL remaining space */ /* Two-thirds /
one-third split */ .split { grid-template-columns: 2fr 1fr; } /* First column
gets 2/3; second gets 1/3 of available space */
7.3 Grid Container Properties
Property Example Description
display grid | inline-grid Activates Grid on the container
grid-template-columns repeat(3, 1fr) Defines the column tracks
grid-template-rows auto 1fr auto Defines the row tracks
Property Example Description
grid-template-areas Named string map Assigns names to grid areas for
placement
gap 1rem or 1rem 2rem Space between rows and columns
(row-gap / column-gap)
align-items start | end | center | Aligns items in the row (block) axis
stretch
justify-items start | end | center | Aligns items in the column (inline)
stretch axis
place-items center Shorthand for align-items + justify-
items
7.4 Grid Item Properties
Property Example Description
grid-column 1 / 3 or 1 / span 2 Spans from column line 1 to line 3
(2 columns wide)
grid-row 2 / 4 Spans from row line 2 to line 4 (2
rows tall)
grid-area header Places item in named grid area
align-self center Overrides align-items for this item
justify-self end Overrides justify-items for this
item
7.5 Annotated Grid Examples
/* === EXAMPLE 1: Basic 3-Column Card Grid === */ .card-grid { display:
grid; grid-template-columns: repeat(3, 1fr); /* 3 equal columns */ gap:
1.5rem; /* Space between cards */ } /* Cards
automatically fill the grid cells in order */ /* === EXAMPLE 2: Responsive
Grid with auto-fill === */ .responsive-grid { display: grid; grid-
template-columns: repeat(auto-fill, minmax(280px, 1fr)); /* auto-fill:
creates as many columns as fit in the container minmax(280px, 1fr): each
column is min 280px, max 1fr RESULT: responsive grid with no media
queries needed! */ gap: 1.5rem; } /* === EXAMPLE 3: Named Grid Areas (Full
Page Layout) === */ .page-layout { display: grid; grid-template-areas:
"header header header" "sidebar main main " "footer footer
footer"; grid-template-columns: 250px 1fr 1fr; grid-template-rows: auto
1fr auto; min-height: 100vh; gap: 0; } /* Assign each element to a named
area */ .site-header { grid-area: header; } .sidebar { grid-area: sidebar;
} .main-content{ grid-area: main; } .site-footer { grid-area: footer; } /*
The grid-template-areas map must be rectangular — no L-shapes */ /* Use "."
for empty cells: "header . ." */ /* === EXAMPLE 4: Item spanning columns/rows
=== */ .grid { display: grid; grid-template-columns: repeat(4, 1fr);
gap: 1rem; } .featured-item { grid-column: 1 / 3; /* Spans columns 1 and 2
(lines 1 to 3) */ grid-row: 1 / 3; /* Spans rows 1 and 2 (lines 1 to 3)
*/ } /* === EXAMPLE 5: Holy Grail Layout === */ .holy-grail { display:
grid; grid-template-columns: 200px 1fr 160px; grid-template-rows: auto 1fr
auto; grid-template-areas: "header header header" "nav main
aside " "footer footer footer"; min-height: 100vh; }
⚠️NOTE: auto-fill vs auto-fit
auto-fill creates empty column tracks if there are fewer items than columns will allow. auto-
fit collapses empty tracks to zero, letting items stretch to fill the row. For card grids where you
want items to fill available width, prefer auto-fit. For photo galleries where you want consistent
column sizes even with few items, use auto-fill.
7.6 Quick Reference Checklist
● Use Grid for two-dimensional (rows + columns) layouts
● Use named grid areas (grid-template-areas) for full-page layouts
● Use repeat(auto-fit, minmax()) for responsive grids without media queries
● Apply gap instead of margins for spacing between grid items
● Combine Grid for page structure with Flexbox inside grid cells for component layout
● Never skip using fr when you want flexible proportional sizing
● Test grid layout in DevTools — the Grid inspector overlay shows all lines and areas
7.7 Practice Exercises
23. Magazine Layout: Using CSS Grid with named areas, recreate a magazine-style layout with a full-
width header, three-column content area (sidebar, main, aside), and full-width footer. Use
different background colors to distinguish each area.
24. Responsive Photo Gallery: Build a photo gallery using repeat(auto-fill, minmax(200px,
1fr)). Add at least 9 placeholder images. One image should span two columns using grid-
column: span 2.
25. Comparison Table: Explore CSS Grid inspector in Chrome/Edge DevTools. Open the Elements
panel, select a grid container, and click the grid badge. Study what the overlay shows about lines
and tracks.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 7: CSS Layout — Grid
Section 8: Responsive Web Design
8.1 Overview
Responsive Web Design (RWD) is an approach to web design that makes pages render well on all screen
sizes — from a 320px wide phone to a 2560px ultrawide monitor. Coined by Ethan Marcotte in 2010,
RWD is built on three pillars: fluid layouts (using relative units instead of fixed pixels), flexible images
(images that scale within their containers), and CSS media queries (rules that apply styles conditionally
based on device characteristics).
The mobile-first approach means writing base CSS for the smallest screen first, then using min-width
media queries to progressively add styles as the screen gets larger. This is the modern standard and
produces leaner, faster-loading CSS compared to starting desktop-first and overriding everything for
mobile.
8.2 The Viewport Meta Tag
This tag (covered in Section 3) is the prerequisite for ALL responsive design:
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!--
Without this, mobile browsers render at ~980px and zoom out --> <!-- With it,
1 CSS pixel = 1 device-independent viewport pixel -->
8.3 Media Queries
/* Mobile-first approach: write base styles for mobile first */ body { font-
size: 1rem; padding: 1rem; } .nav-links { display: none; /* Hidden by
default on mobile (hamburger menu) */ } /* Tablet and above: 768px */ @media
(min-width: 768px) { body { padding: 2rem; } .nav-links
{ display: flex; /* Show nav links on tablet+ */ gap:
2rem; } .cards { grid-template-columns: repeat(2, 1fr); /* 2 columns
on tablet */ } } /* Laptop and above: 1024px */ @media (min-width: 1024px)
{ .cards { grid-template-columns: repeat(3, 1fr); /* 3 columns on laptop
*/ } .container { max-width: 1200px; margin: 0 auto; /* Center
content with auto margins */ } } /* Desktop and above: 1280px */ @media
(min-width: 1280px) { .cards { grid-template-columns: repeat(4, 1fr); /*
4 columns on desktop */ } } /* You can also target specific features: */
@media (prefers-color-scheme: dark) { /* Dark mode styles (if you support
it) */ } @media print { .navbar, .sidebar { display: none; } } @media
(prefers-reduced-motion: reduce) { *, *::before, *::after { animation-
duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
8.4 Common Breakpoints
Breakpoint Target Devices Typical Usage
480px Small phones (landscape) Adjust small UI elements
768px Tablets, large phones Switch to 2-column layouts, show
nav
1024px Laptops, tablets landscape Switch to 3-column layouts
1280px Desktop monitors Full layout, max-width containers
1536px Large/wide desktops Larger typography, wider content
💡 TIP: Breakpoints Should Match Your Content
The best breakpoints are determined by where your content breaks, not by specific device widths.
Use DevTools to slowly resize the browser window and add a breakpoint when the layout starts to
look awkward — not before. Targeting specific device widths is a maintenance headache as devices
change.
8.5 Responsive Images
/* CSS: Always apply this globally */ img { max-width: 100%; /* Image never
exceeds its container */ height: auto; /* Maintains aspect ratio */
display: block; /* Removes the default inline gap below images */ } /*
HTML: srcset for different resolutions */ <img srcset="images/[Link]
480w, images/[Link] 768w, images/[Link]
1280w" sizes="(max-width: 480px) 100vw, (max-width: 768px) 100vw,
1280px" src="images/[Link]" alt="Panoramic view of New Braunfels,
Texas at sunset" width="1280" height="720" loading="lazy"> <!-- srcset:
list of image files with their natural width (w descriptor) --> <!-- sizes:
tells browser how wide the image will be at each breakpoint --> <!-- Browser
picks the most appropriate image based on screen + density --> <!-- picture
element: art direction (different crops for different sizes) --> <picture>
<source media="(max-width: 768px)" srcset="images/[Link]"> <source
media="(max-width: 1280px)" srcset="images/[Link]"> <img
src="images/[Link]" alt="Hero image" loading="lazy"
width="1280" height="720"> </picture>
8.6 Responsive Typography with clamp()
/* clamp(minimum, preferred, maximum) */ /* Typography that scales fluidly
between viewport sizes */ h1 { font-size: clamp(1.75rem, 4vw, 3.5rem); /*
At narrow viewports: minimum 1.75rem (28px) */ /* At wide viewports:
maximum 3.5rem (56px) */ /* In between: scales with 4% of viewport width
*/ } p { font-size: clamp(1rem, 1.5vw, 1.25rem); } /* Responsive line
length for readability */ .content { max-width: 65ch; /* Optimal reading
width: 55-75 characters */ }
8.7 Responsive Navigation — Annotated Example
<!-- HTML --> <header> <nav class="navbar"> <a href="/"
class="logo">Bob's Site</a> <button class="hamburger" aria-label="Toggle
navigation" aria-expanded="false"> ☰ </button> <ul class="nav-
links"> <li><a href="/">Home</a></li> <li><a
href="/[Link]">About</a></li> <li><a
href="/[Link]">Contact</a></li> </ul> </nav> </header> /* === CSS
(Mobile First) === */ .navbar { display: flex; justify-content: space-
between; align-items: center; padding: 1rem 1.5rem; background-color:
#1e3a8a; } .nav-links { display: none; /* Hidden on mobile */ list-style:
none; padding: 0; margin: 0; } .hamburger { display: block; } /* Shown on
mobile */ @media (min-width: 768px) { .nav-links { display: flex; /*
Shown on tablet+ */ gap: 2rem; } .hamburger { display: none; } /*
Hidden on tablet+ */ }
8.8 Quick Reference Checklist
● Viewport meta tag is in the <head> of every HTML page
● Base styles written for mobile; min-width queries add larger-screen styles
● All images have max-width: 100%; height: auto; in CSS
● No fixed pixel widths on containers (use %, max-width, or fr units)
● Tested in DevTools device emulator at 375px, 768px, and 1280px
● Responsive images use srcset for different resolutions
● Typography uses clamp() or rem + media queries for scaling
● prefers-reduced-motion media query respected for animations
8.9 Practice Exercises
26. Convert: Take a fixed-width layout you built in Sections 5-7 and convert it to fully responsive
using mobile-first CSS and media queries at 768px and 1024px.
27. Navigation: Implement the responsive navigation example above. Add JavaScript to toggle a CSS
class on the nav-links when the hamburger button is clicked. Verify the menu opens/closes
and the hamburger hides at 768px+.
28. clamp() Typography: Apply clamp() to all headings on a page. Use Chrome DevTools to drag
the viewport width and watch headings scale smoothly.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 8: Responsive Web Design
Section 9: CSS Typography & Color
9.1 Overview
Typography is the art of arranging type to make text readable and beautiful. On the web, good
typography means choosing fonts that load fast, scale well, and match your brand tone. Color,
meanwhile, communicates mood, guides attention, and must meet accessibility contrast requirements
to be legally and ethically inclusive. Together, typography and color form the visual identity of a website.
9.2 Font Stacks
A font stack is a comma-separated list of font families. The browser uses the first available font; if not
installed, it moves to the next. Always end with a generic family (serif, sans-serif, monospace).
/* Modern system font stacks (no downloads required — fast!) */ /* System UI
(used by many modern design systems) */ font-family: system-ui, -apple-system,
BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-
serif; /* Serif: for long-form reading */ font-family: Georgia, 'Times New
Roman', Times, serif; /* Monospace: for code */ font-family: 'Cascadia Code',
Consolas, 'Courier New', monospace;
9.3 Google Fonts
<!-- Step 1: Add to <head> BEFORE your stylesheet --> <link rel="preconnect"
href="[Link] <link rel="preconnect"
href="[Link] crossorigin> <link
href="[Link]
&family=Merriweather:ital,wght@0,400;1,400&display=swap"
rel="stylesheet"> /* Step 2: Use in CSS */ body { font-family: 'Inter',
system-ui, sans-serif; } h1, h2, h3 { font-family: 'Merriweather', Georgia,
serif; } /* display=swap: prevents invisible text while font loads.
Browsers show fallback font first, then swap when loaded. */
💡 TIP: Limit Your Fonts
Use no more than 2 font families per project — one for headings, one for body. Each additional
font is an HTTP request that slows page load. Use font-weight variations (400, 600, 700) of the
same font for visual hierarchy rather than loading a third font.
9.4 Typography Properties
body { font-family: 'Inter', system-ui, sans-serif; font-size: 1rem;
/* 16px — never set smaller for body text */ font-weight: 400; /*
100 (thin) to 900 (black); 400=normal, 700=bold */ font-style: normal;
/* normal | italic | oblique */ line-height: 1.6; /* Recommended:
1.4–1.6 for body text */ letter-spacing: 0; /* Normal; positive =
more space between chars */ word-spacing: 0; /* Extra space
between words */ text-align: left; /* left | center | right |
justify */ text-indent: 0; /* First-line indent (rare on web) */
color: #1a1a1a; } h1 { font-size: clamp(2rem, 4vw, 3.5rem); font-weight:
700; line-height: 1.2; /* Headings look better with tighter line-height */
letter-spacing: -0.02em; /* Slightly tighten large headings */ } /* Text
overflow — truncate with ellipsis */ .card-title { white-space: nowrap;
/* Prevent text wrapping */ overflow: hidden; /* Hide overflowing
text */ text-overflow: ellipsis; /* Show "..." where text is cut off */ }
/* Uppercase navigation links */ .nav a { text-transform: uppercase;
letter-spacing: 0.08em; /* Uppercase text benefits from extra spacing */
font-size: 0.875rem; }
9.5 CSS Color Formats
Format Example Notes
Named color color: blue; Limited palette (147 names); avoid
for design systems
Hex (6-digit) color: #2563eb; Most common; #RRGGBB format
Hex (3-digit shorthand) color: #26e; Same as #2266ee — only works
Format Example Notes
when digits repeat
rgb() color: rgb(37, 99, 235); Red, Green, Blue values 0–255
rgba() color: rgba(37, 99, 235, With alpha (transparency) 0–1
0.5);
hsl() color: hsl(221, 83%, 53%); Hue (0–360°), Saturation %,
Lightness %
hsla() color: hsla(221, 83%, 53%, HSL with alpha transparency
0.8);
oklch() color: oklch(60% 0.2 250); Modern perceptual color space —
superior for gradients
💡 TIP: Use HSL for Design Systems
HSL makes it easy to create consistent color palettes. Keep the Hue the same and vary Lightness to
create shades: hsl(221, 83%, 20%) (very dark), hsl(221, 83%, 53%) (base), hsl(221,
83%, 80%) (light), hsl(221, 83%, 95%) (very light). This is exactly how Tailwind CSS's color
system works.
9.6 Annotated Color Palette Using CSS Variables
:root { /* Primary brand color — blue */ --color-primary-900: hsl(221,
83%, 20%); /* Very dark blue */ --color-primary-700: hsl(221, 83%, 35%);
/* Dark blue */ --color-primary-500: hsl(221, 83%, 53%); /* Base blue */
--color-primary-300: hsl(221, 83%, 72%); /* Light blue */ --color-primary-
100: hsl(221, 83%, 93%); /* Very light blue */ /* Neutral grays */ --
color-gray-900: #111827; --color-gray-700: #374151; --color-gray-500:
#6b7280; --color-gray-300: #d1d5db; --color-gray-100: #f3f4f6; /*
Semantic colors */ --color-success: hsl(142, 71%, 45%); /* Green */ --
color-warning: hsl(38, 92%, 50%); /* Amber */ --color-danger: hsl(0, 84%,
60%); /* Red */ --color-info: hsl(199, 89%, 48%); /* Cyan */ /*
Text */ --color-text-dark: var(--color-gray-900); --color-text-body:
var(--color-gray-700); --color-text-muted: var(--color-gray-500); /*
Backgrounds */ --color-bg: #ffffff; --color-bg-subtle: var(--
color-gray-100); --color-bg-emphasis: var(--color-primary-100); }
9.7 Color Accessibility — Contrast Requirements
WCAG 2.1 (Web Content Accessibility Guidelines) sets minimum contrast ratio requirements for text
against its background. Contrast ratio is calculated as a ratio of the relative luminance of the two colors:
WCAG Level Normal Text (<18pt) Large Text (≥18pt bold, UI Components
≥24pt)
AA (Minimum — legal 4.5 : 1 3:1 3:1
standard)
AAA (Enhanced) 7:1 4.5 : 1 N/A
Testing contrast:
● Chrome/Edge DevTools: Click any color value in the Styles panel — the picker shows a contrast
ratio live.
● WebAIM Contrast Checker: [Link]/resources/contrastchecker
● Lighthouse audit (DevTools) includes color contrast issues.
9.8 Quick Reference Checklist
● Body font size at least 16px (1rem) — smaller text is hard to read
● Line height at least 1.4 (1.5–1.6 recommended for body text)
● Maximum 2 font families on any page
● Google Fonts loaded with display=swap to prevent invisible text
● All text color contrast meets WCAG AA (4.5:1 for body, 3:1 for large text)
● No justified text — it creates uneven spacing ("rivers") on screen
● Content columns limited to 55-75 characters wide for readability
● Color not used as the only means of conveying information
9.9 Practice Exercises
29. Google Font: Choose two Google fonts (one sans-serif for body, one serif for headings). Embed
them in an HTML page and apply them with CSS. Adjust font sizes, line heights, and letter
spacing for the best readability.
30. Color Palette: Using the CSS variable structure above as a template, build a complete color
palette for a fictional website. Define at least 8 variables including primary, text, and background
colors.
31. Contrast Audit: Open a website you use regularly. Open DevTools, go to the Lighthouse tab, and
run an Accessibility audit. How many contrast issues does it find? Try the WebAIM Contrast
Checker on your own color choices.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 9: CSS Typography & Color
Section 10: CSS Backgrounds, Borders & Effects
10.1 Overview
Beyond layout and typography, CSS provides powerful tools for visual decoration: gradients, background
images, shadows, rounded corners, 2D/3D transforms, and smooth CSS animations. When used with
restraint and purpose, these properties elevate a design from flat to polished. When overused, they
create visual noise. The professional approach is: every visual effect should serve a purpose — drawing
attention, communicating state, or delighting the user.
10.2 Background Properties
/* Background color */ .element { background-color: #f3f4f6; } /* Background
image */ .hero { background-image: url('images/[Link]'); background-
repeat: no-repeat; /* no-repeat | repeat | repeat-x | repeat-y */
background-size: cover; /* cover: fills container (may crop)
contain: fits inside container */ background-position: center center; /*
horizontal vertical */ background-attachment: fixed; /* Parallax
effect (use cautiously) */ } /* Shorthand (image repeat position / size
attachment) */ .hero { background: url('images/[Link]') no-repeat center
center / cover; } /* Multiple backgrounds (stacked top to bottom) */ .layered
{ background: url('images/[Link]') repeat, /*
Layer 1 (top) */ url('images/[Link]') no-repeat center / cover; /*
Layer 2 (bottom) */ } /* === GRADIENTS === */ /* Linear gradient
*/ .gradient-bg { background: linear-gradient(135deg, #2563eb,
#7c3aed); /* 135deg = diagonal; first color at start, second at end */ } /*
Gradient with multiple stops */ .multi-gradient { background: linear-
gradient(to right, #2563eb 0%, #3b82f6 40%, #7c3aed 100%); } /*
Radial gradient (sunburst) */ .radial { background: radial-gradient(circle
at center, #eff6ff, #2563eb); } /* Repeating gradient (stripes) */ .stripes {
background: repeating-linear-gradient( 45deg, #e5e7eb 0px, #e5e7eb
10px, #ffffff 10px, #ffffff 20px ); }
10.3 Borders & Outlines
/* Border shorthand: width style color */ .card { border: 1px solid #e5e7eb; }
/* Individual sides */ .highlight { border-left: 4px solid #2563eb; } /*
Border radius: rounded corners */ .rounded { border-radius:
8px; } /* All corners */ .circle { border-radius: 50%; } /*
Perfect circle (equal width/height) */ .pill { border-radius: 9999px; }
/* Pill / capsule shape */ .custom { border-radius: 4px 16px 4px
16px; } /* TL TR BR BL */ /* Outline: renders OUTSIDE the border; does not
affect layout */ .focused { outline: 2px solid #2563eb; outline-offset:
2px; } /* DO NOT set outline: none without a replacement — it breaks keyboard
a11y! */
10.4 Shadows
/* box-shadow: offset-x offset-y blur-radius spread-radius color */ .card
{ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), /* Small soft shadow */
0 1px 2px rgba(0, 0, 0, 0.06); /* Multiple shadows for realism */ } .card-
elevated { box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); /* Lifted card */ }
.inset-shadow { box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1); /* Inner
shadow */ } /* text-shadow: offset-x offset-y blur color */ .hero-title
{ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); /* Readable text on images */ }
/* drop-shadow() filter (follows irregular shapes, unlike box-shadow)
*/ .logo-svg { filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); }
10.5 Transforms
/* Transforms do NOT affect layout — other elements don't shift */ .element {
transform: translateX(20px); /* Move right 20px */ transform:
translateY(-10px); /* Move up 10px */ transform: translate(-50%, -
50%); /* Classic centering trick */ transform: scale(1.05); /*
Scale up 5% */ transform: scale(0.95); /* Scale down 5% */
transform: rotate(45deg); /* Rotate 45 degrees clockwise */
transform: skew(10deg, 5deg); /* Skew (rarely used) */ } /* Multiple
transforms (chain with space) */ .card:hover { transform: translateY(-4px)
scale(1.02); /* Lift AND scale on hover */ } /* Transform origin: pivot point
for rotation/scale */ .badge { transform-origin: top right; transform:
rotate(15deg); /* Rotates around top-right corner */ }
10.6 Transitions
/* Transitions: smooth property changes over time */ /* Apply to the BASE
state, not the :hover state */ .button { background-color: #2563eb;
color: #ffffff; padding: 0.75rem 1.5rem; border: none; cursor: pointer;
/* transition: property duration timing-function delay */ transition:
background-color 200ms ease, transform 150ms
ease; } .button:hover { background-color: #1d4ed8; /* Smoothly
transitions from #2563eb */ transform: translateY(-2px); /* Smoothly lifts
on hover */ } .button:active { transform: translateY(0); /* Returns to
original position on click */ } /* Common timing functions */ /* ease
(default): slow start, fast middle, slow end */ /* linear: constant speed
*/ /* ease-in: slow start */ /* ease-out: slow end (most natural-feeling for
exits) */ /* ease-in-out: slow start and end */ /* cubic-bezier(0.25, 0.1,
0.25, 1): custom curve */ /* Transitioning ALL properties (avoid — can cause
performance issues) */ /* transition: all 200ms ease; */ /* Better: only
transition specific properties you need */ .card { transition: box-shadow
200ms ease, transform 200ms ease; } .card:hover { box-shadow: 0 10px 25px
rgba(0,0,0,0.15); transform: translateY(-4px); }
10.7 CSS Animations
/* Step 1: Define the animation with @keyframes */ @keyframes fadeInUp
{ from { opacity: 0; transform: translateY(20px); } to
{ opacity: 1; transform: translateY(0); } } @keyframes spin
{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
/* Step 2: Apply the animation */ .hero-content { animation-name: fadeInUp;
animation-duration: 600ms; animation-timing-function: ease-out; animation-
delay: 200ms; /* Wait 200ms before starting */ animation-iteration-
count: 1; /* How many times (or 'infinite') */ animation-direction: normal;
/* normal | reverse | alternate */ animation-fill-mode: both; /* 'both'
applies 'from' style before start */ /* Shorthand: name duration timing-
function delay count direction fill-mode */ animation: fadeInUp 600ms ease-
out 200ms 1 normal both; } /* Loading spinner */ .spinner { width: 40px;
height: 40px; border: 4px solid #e5e7eb; border-top-color: #2563eb;
border-radius: 50%; animation: spin 800ms linear infinite; } /* Respect
user preferences for reduced motion */ @media (prefers-reduced-motion: reduce)
{ *, *::before, *::after { animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important; transition-duration: 0.01ms !
important; } }
10.8 Quick Reference Checklist
● Transitions on the base state (not the :hover state)
● Use transform and opacity for animations — they are GPU-accelerated
● Avoid animating width, height, margin, or padding — they trigger layout recalculations
● prefers-reduced-motion media query implemented for all animations
● Transition duration: 150–300ms for interactions; 500–800ms for entrances
● Focus styles (:focus-visible) are always visible — never outline: none without a
replacement
● Gradients only degrade to background-color if the image fails
10.9 Practice Exercises
32. Animated Card Hover: Build a card with an image, title, and description. On hover: lift the card
with translateY(-8px), increase box-shadow depth, and slightly scale up the image. All with
CSS transitions.
33. CSS Loading Spinner: Create a pure CSS animated loading spinner using @keyframes and the
border technique shown above. Add a play/pause button using JavaScript to toggle a paused
animation state class.
34. Gradient Hero Banner: Build a hero section with a diagonal linear gradient background, white
text, and a subtle animated pulse on the call-to-action button. Make it respect prefers-
reduced-motion.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 10: CSS Backgrounds, Borders & Effects
Section 11: Images & Media on the Web
11.1 Overview
Images are the largest contributors to web page weight and load time. Choosing the wrong file format,
skipping compression, or serving desktop-sized images to mobile phones are among the most common
performance mistakes. This section covers every major image format, when to use each, how to
optimize images before uploading, and how to implement responsive images in HTML.
11.2 Image Format Decision Table
Format Compression Transparency Animation Best For Avoid For
JPEG Lossy No No Photographs, Logos, icons,
complex text-heavy
images with images
gradients (artifacts)
Format Compression Transparency Animation Best For Avoid For
PNG Lossless Yes (alpha) No Logos with Large
transparency, photographs
screenshots, (file size too
icons large)
GIF Lossless Yes (binary) Yes Simple Photos,
animations modern
(legacy) animations (use
WebP/video
instead)
SVG N/A (vector) Yes Yes (CSS) Icons, logos, Photographs,
illustrations, UI complex
graphics realistic images
WebP Lossy & Yes Yes Everything — Older browser
Lossless modern support (use
replacement with fallback)
for JPEG/PNG
AVIF Lossy & Yes Yes Next-gen: Broad support
Lossless smallest files, still catching up
best quality (use with
fallback)
💡 TIP: Use WebP as Your Primary Format
WebP images are typically 25–35% smaller than JPEG at equivalent quality, and up to 50% smaller
than PNG — with full transparency support. All major modern browsers support WebP. Use the
<picture> element with JPEG/PNG as fallback for any users on very old browsers.
11.3 Image Optimization Techniques
● Resize before upload: Never upload a 4000×3000px photo and rely on HTML/CSS to shrink it.
Resize to the actual display size first using a tool like Photoshop, GIMP, or [Link].
● Compress images: Use [Link] (free, browser-based) or TinyPNG/TinyJPEG to compress
without significant quality loss. Target under 100KB for most images; under 200KB for hero
images.
● Use correct formats: Convert JPEG/PNG photos to WebP. Keep SVGs for any graphic that needs
to scale.
● Serve appropriate sizes: Use srcset to serve smaller files to smaller screens (Section 8).
● Lazy loading: Add loading="lazy" to all images below the fold. The browser only downloads
them when they are about to enter the viewport.
● Specify dimensions: Always set width and height attributes on <img> to prevent Cumulative
Layout Shift (CLS) — one of Google's Core Web Vitals.
11.4 Responsive Images in HTML
<!-- srcset with width descriptors: browser chooses best option --> <img
srcset="images/[Link] 480w, images/[Link] 768w,
images/[Link] 1280w" sizes="(max-width: 480px) 100vw,
(max-width: 768px) 100vw, 1280px" src="images/[Link]"
alt="Aerial view of New Braunfels, TX showing the Comal River" width="1280"
height="720" loading="lazy" decoding="async"> <!-- picture element: art
direction (different crops for different contexts) --> <picture> <!-- Modern
browsers: try AVIF first (smallest) --> <source srcset="images/hero-
[Link] 480w, images/[Link] 1280w" type="image/avif"> <!--
Fallback: WebP (widely supported) --> <source srcset="images/hero-
[Link] 480w, images/[Link] 1280w" type="image/webp"> <!--
Final fallback: JPEG (universal support) --> <img src="images/hero-
[Link]" alt="Hero image description" width="1280" height="720"
loading="eager"> <!-- loading="eager" for above-the-fold images — load
immediately --> </picture>
11.5 Background Images vs Content Images
Use Case Use HTML <img> Use CSS background-image
Product photos ✅ Yes — content, needs alt text ❌ No — invisible to screen readers
Article illustrations ✅ Yes — part of content ❌ No
Hero background Possible with positioning ✅ Yes — purely decorative
Decorative texture/pattern ❌ No ✅ Yes — decorative only
Logos ✅ Yes — use SVG or PNG with alt ❌ No — inaccessible
text
11.6 SVG — The Ideal Format for Icons and Logos
<!-- Method 1: SVG as img src (simple, cached, but not styleable via CSS) -->
<img src="icons/[Link]" alt="Right arrow" width="24" height="24"> <!--
Method 2: Inline SVG (fully styleable, not cached separately) --> <svg
xmlns="[Link] width="24" height="24" viewBox="0 0 24
24" aria-hidden="true" focusable="false"> <path d="M5 12h14M12 5l7 7-7 7"
stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg>
<!-- currentColor inherits text color from CSS — powerful for theming --> <!--
aria-hidden="true" for decorative icons (no screen reader announcement) -->
11.7 Embedded Video
<video controls <!-- Show browser default video controls -->
poster="[Link]" <!-- Image shown before video plays --> width="800"
height="450" preload="metadata"> <!-- Load metadata only; not the full
video --> <!-- Multiple sources for browser compatibility --> <source
src="video/[Link]" type="video/webm"> <source src="video/demo.mp4"
type="video/mp4"> <!-- Fallback text for browsers that cannot play video --
> <p>Your browser does not support HTML video. <a
href="video/demo.mp4">Download the video</a></p> </video> <!-- Autoplay video
(must be muted for browsers to allow) --> <video autoplay muted loop
playsinline aria-label="Product demonstration animation"> <source
src="video/[Link]" type="video/webm"> <source src="video/hero-
loop.mp4" type="video/mp4"> </video>
11.8 Quick Reference Checklist
● All <img> elements have descriptive alt text (or alt="" if decorative)
● Images are compressed before uploading (target under 100KB for most)
● Modern formats used: WebP for photos, SVG for icons/logos
● loading="lazy" on all below-the-fold images
● width and height attributes set on all <img> elements
● Responsive images use srcset for different screen sizes
● Global CSS: img { max-width: 100%; height: auto; }
● Video has a poster image and captions/subtitles for accessibility
● Autoplay video is always muted (required by modern browsers)
11.9 Practice Exercises
35. Format Comparison: Take one photograph and export it in JPEG (quality 80%), WebP (quality
80%), and AVIF (if your tool supports it). Compare file sizes and visual quality. What percentage
smaller is WebP vs JPEG?
36. srcset Implementation: Create three versions of a hero image at widths 480px, 768px, and
1280px. Implement srcset and sizes in HTML. Use Chrome DevTools Network tab to verify
which image loads at each simulated screen size.
37. Video Page: Embed a video (use a Creative Commons video from [Link]) using the
<video> element with controls, a poster image, and multiple source formats. Style a caption
below it using <figure> and <figcaption>.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 11: Images & Media on the Web
Section 12: Web Accessibility (a11y)
12.1 Overview
Web accessibility means designing and building websites that people with disabilities can perceive,
understand, navigate, and interact with effectively. "a11y" is a numeronym for accessibility (11 letters
between 'a' and 'y'). Disabilities relevant to web use include visual (blindness, low vision, color
blindness), auditory (deafness, hard of hearing), motor (inability to use a mouse, tremors), and cognitive
(dyslexia, attention disorders) conditions.
Accessibility is not just an ethical responsibility — it is increasingly a legal requirement. In the United
States, the Americans with Disabilities Act (ADA) has been interpreted to apply to websites. The EU's
European Accessibility Act mandates compliance for many digital services. Building accessibly from the
start is far easier than retrofitting it later, and the same practices that help users with disabilities often
improve the experience for all users: better contrast helps in bright sunlight; keyboard navigation helps
power users; clear structure helps everyone.
12.2 The POUR Principles (WCAG 2.1)
Principle Meaning Key Requirements
Perceivable Information must be presentable Alt text, captions, sufficient
to users in ways they can perceive contrast, text can be resized
Operable Interface components and Keyboard accessible, no seizure-
navigation must be operable inducing content, enough time to
interact
Principle Meaning Key Requirements
Understandable Information and UI operation must Readable text, predictable
be understandable behavior, input assistance and
error messages
Robust Content must be interpreted by a Valid HTML, ARIA used correctly,
wide range of user agents and compatible with current and
assistive technologies future tools
12.3 Semantic HTML as the Foundation of Accessibility
The single most effective accessibility technique is writing proper semantic HTML. When you use
<button> instead of a styled <div>, you get keyboard operability, focus management, and role
announcements for free. When you use <label> with <input>, screen readers announce the label
when the input is focused. Semantic HTML gives assistive technologies the information they need to
help users.
<!-- WRONG: inaccessible div-button --> <div class="btn"
onclick="submit()">Submit</div> <!-- Not keyboard accessible, not announced as
a button, no Enter key support --> <!-- RIGHT: semantic button --> <button
type="submit">Submit</button> <!-- Keyboard accessible (Tab to focus,
Enter/Space to activate), correct role --> <!-- WRONG: inaccessible
navigation --> <div class="nav"> <span onclick="...">Home</span> </div>
<!-- RIGHT: semantic navigation --> <nav aria-label="Main navigation"> <ul>
<li><a href="/">Home</a></li> </ul> </nav>
12.4 ARIA — Accessible Rich Internet Applications
ARIA attributes add semantic information to HTML when native semantics are insufficient for complex
interactive patterns. The first rule of ARIA is: do not use ARIA if a native HTML element or attribute
provides the needed accessibility semantics.
Attribute Purpose Example
role Defines element's purpose (when role="alert" on error messages
HTML semantics insufficient)
aria-label Provides accessible name when no <button aria-label="Close
visible text label exists dialog">✕</button>
aria-labelledby References another element's ID aria-labelledby="dialog-
as the accessible name title"
aria-describedby References additional description Links input to its error message
for an element element
Attribute Purpose Example
aria-hidden="true" Hides element from screen Decorative icons, duplicate text
readers (decorative content)
aria-expanded Indicates if a control is expanded Accordion, dropdown, hamburger
or collapsed menu
aria-live Announces dynamic content aria-live="polite" for status
changes to screen readers updates
aria-required Indicates field is required aria-required="true"
(supplement, not replace,
required)
12.5 Keyboard Navigation
Many users cannot use a mouse. They navigate with the Tab key (forward), Shift+Tab (backward), arrow
keys (within components), Enter (activate), and Escape (dismiss). Your site must be fully usable this way.
/* NEVER do this without a replacement focus style */ *:focus { outline: none;
} /* ❌ BREAKS keyboard navigation */ /* DO THIS instead: custom focus style
*/ *:focus-visible { outline: 2px solid #2563eb; outline-offset: 3px; } /*
:focus-visible only shows focus ring for keyboard navigation, not on mouse
click — best of both worlds */ /* Skip link: lets keyboard users jump past
repetitive navigation */ .skip-link { position: absolute; top: -100%;
/* Hidden off-screen normally */ left: 0; background: #2563eb; color:
#ffffff; padding: 0.5rem 1rem; z-index: 9999; } .skip-link:focus { top:
0; /* Visible when focused via keyboard */ } /* tabindex controls
keyboard focus order */ /* tabindex="0" : adds to natural tab order */ /*
tabindex="-1" : focusable only via JavaScript (not tab key) */ /*
tabindex="1+" : AVOID — creates unpredictable tab order */
12.6 Alt Text Writing Guide
● Describe the purpose: What does a sighted user learn from this image? Write that.
● Be concise: Typically 5–15 words. Long descriptions use aria-describedby referencing a
separate paragraph.
● Don't start with "Image of" or "Photo of" — screen readers already announce it as an image.
● Decorative images: Use alt="" — the screen reader skips it entirely.
● Functional images (buttons, links): Describe the function, not the appearance: alt="Search"
not alt="Magnifying glass icon".
● Charts and graphs: Describe the key takeaway: alt="Line chart showing user growth
from 1,000 in January to 8,500 in December 2026".
12.7 Accessible Forms
<form> <!-- Always associate labels with inputs --> <label for="email">
Email Address <span aria-hidden="true" style="color: red;"> *</span>
</label> <input type="email" id="email" name="email" required
aria-required="true" aria-describedby="email-error"
autocomplete="email"> <!-- Error message (shown when invalid) --> <span
id="email-error" role="alert" aria-live="polite"> <!-- JS inserts error
message here --> </span> <!-- Required field indicator --> <p><span
aria-hidden="true">*</span> Required fields</p> </form>
12.8 Accessibility Testing Tools
Tool Type How to Use
axe DevTools Browser extension (Chrome/Edge) Open DevTools → axe tab → Scan
Page → Review violations
Lighthouse Built into Chrome/Edge DevTools DevTools → Lighthouse →
Accessibility → Run audit
WAVE Browser extension + web tool Visit [Link] or install
extension; visual overlay of issues
Accessibility Tree Built into Chrome/Edge DevTools Elements panel → Accessibility tab
→ see how screen readers see the
element
Keyboard testing Manual Tab through your entire page. Can
you reach and activate everything?
NVDA Free screen reader (Windows) Download from [Link]; test
how your page sounds to screen
reader users
12.9 Quick Reference Checklist
● lang attribute on <html> element
● All interactive elements reachable and operable by keyboard
● Focus styles are visible — never outline: none without replacement
● Skip navigation link at the top of every page
● Color contrast meets WCAG AA (4.5:1 normal text, 3:1 large text)
● Color not used as the sole means of conveying information
● All images have appropriate alt attributes
● All form inputs have associated <label> elements
● ARIA used sparingly and correctly — HTML semantics first
● No content conveyed by CSS alone (e.g., background images that are informational)
● Page has been tested with axe or Lighthouse
12.10 Practice Exercises
38. Axe Audit: Run the axe DevTools extension on three different websites (try a local business site,
a major news site, and a government site). Document the accessibility violations found on each.
Which is the most accessible?
39. Skip Navigation: Add a visually hidden but focusable skip-to-content link to one of your projects.
Test that it appears when you Tab to it and jumps focus to the main content area when
activated.
40. Fix 5 Errors: Take a webpage with accessibility issues and fix: missing alt text, a form input
without a label, a link that says "click here", an element with insufficient color contrast, and a
custom interactive element that is not keyboard accessible.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 12: Web Accessibility (a11y)
Section 13: JavaScript Foundations
13.1 Overview
JavaScript (JS) is the programming language of the web. While HTML provides structure and CSS
provides style, JavaScript provides behavior — making pages interactive, responding to user actions,
fetching data, validating forms, updating content without a page reload, and much more. Created by
Brendan Eich in 10 days in 1995, JavaScript has grown into one of the world's most widely used
programming languages, running in browsers, on servers ([Link]), in mobile apps, and on the desktop.
Connect JavaScript to HTML using a <script> tag in the <head> with the defer attribute (preferred),
or place it at the bottom of the <body>:
<!-- PREFERRED: In the <head> with defer --> <script src="js/[Link]"
defer></script> <!-- defer: downloads JS in parallel, executes AFTER HTML is
parsed --> <!-- async: downloads in parallel, executes as soon as downloaded
--> <!-- (order not guaranteed — use for independent scripts like analytics)
--> <script src="js/[Link]" async></script> <!-- OLDER approach: script
at bottom of body --> <script src="js/[Link]"></script> </body></html>
13.2 Variables — var, let, const
// var — OLD. Function-scoped, hoisted. AVOID. var oldWay = "don't use this";
// let — Block-scoped. Use when value will change. let count = 0; count =
1; // OK — reassignment allowed // const — Block-scoped. Use when value will
NOT change. const PI = 3.14159; const MAX_RETRIES = 3; // PI = 4; // ERROR —
cannot reassign a const // RULE: Default to const. Use let only if you need
to reassign. // const does NOT mean immutable for objects/arrays (only the
binding): const user = { name: 'Bob' }; [Link] = 'Robert'; // OK —
modifying the object, not rebinding the variable user = {}; // ERROR — cannot
rebind the const
13.3 Data Types
// Primitive types (immutable, compared by value) const text = "Hello, New
Braunfels!"; // string const num = 42; // number
(integers AND decimals) const pi = 3.14; // number
(no separate float type) const isTrue = true; // boolean
const nothing = null; // null (intentional absence of
value) let unknown; // undefined (declared but
not assigned) const big = 9007199254740993n; // bigint (very large
integers) const sym = Symbol('id'); // symbol (unique
identifier) // Reference types (mutable, compared by reference) const arr =
[1, 2, 3, 'Bob', true]; // array const obj = { name: 'Bob', city: 'New
Braunfels' }; // object // Checking types [Link](typeof 42); //
"number" [Link](typeof "hello"); // "string" [Link](typeof true);
// "boolean" [Link](typeof null); // "object" — famous JS quirk!
[Link](typeof undefined); // "undefined" [Link](typeof
[]); // "object" — use [Link]() instead
[Link]([Link]([]));// true
13.4 Operators
// Arithmetic let a = 10 + 5; // 15 let b = 10 - 3; // 7 let c = 4 * 6;
// 24 let d = 15 / 4; // 3.75 let e = 15 % 4; // 3 (remainder/modulo —
very useful!) let f = 2 ** 8; // 256 (exponentiation) // Assignment let x =
10; x += 5; // x = 15 x -= 3; // x = 12 x *= 2; // x = 24 x++; // x =
25 (post-increment) x--; // x = 24 (post-decrement) // Comparison —
ALWAYS use === (strict equality) 5 === 5 // true (same value AND
type) 5 === "5" // false (different types) 5 == "5" // true (==
coerces types — AVOID!) 5 !== 6 // true 10 > 5 // true 10 >=
10 // true // Logical true && false // false (AND — both must be
true) true || false // true (OR — at least one must be true) !true
// false (NOT — inverts boolean) // Nullish coalescing (returns right side
only if left is null/undefined) const name = [Link] ?? 'Anonymous'; //
'Anonymous' if name is null/undefined // Optional chaining (safely access
nested properties) const city = user?.address?.city; // undefined (not an
error) if address is null
13.5 Strings & Template Literals
const firstName = "Bob"; const city = "New Braunfels"; // Concatenation (old
way — messy) const msg1 = "Welcome, " + firstName + "! You're in " + city +
"."; // Template literals (modern — clean, readable) const msg2 = `Welcome, $
{firstName}! You're in ${city}.`; // Use backticks (`); embed expressions with
${} // Multi-line strings const html = ` <div class="card"> <h2>$
{firstName}'s Profile</h2> <p>Location: ${city}, TX</p> </div> `; //
String methods const str = " Hello, World! "; [Link] // 17
[Link]() // "Hello, World!" (removes whitespace)
[Link]() // " HELLO, WORLD! " [Link]() // "
hello, world! " [Link]("World") // true [Link]("World") // 9
[Link]("World", "Bob") // " Hello, Bob! " [Link](2, 7) //
"Hello" [Link](", ") // [" Hello", "World! "] [Link]("
He") // true
13.6 Arrays
const fruits = ["apple", "banana", "cherry"]; // Accessing elements (zero-
indexed) fruits[0] // "apple" fruits[[Link] - 1] // "cherry"
(last element) // Modifying arrays [Link]("date"); // Add to END →
["apple","banana","cherry","date"] [Link](); // Remove from
END → ["apple","banana","cherry"] [Link]("avocado"); // Add to
BEGINNING [Link](); // Remove from BEGINNING // Iterating
[Link](fruit => [Link](fruit)); // Run function on each item //
Transforming (returns NEW array — does not mutate original) const upperFruits
= [Link](f => [Link]()); const longFruits = [Link](f =>
[Link] > 5); const found = [Link](f => [Link]("b")); //
"banana" const hasCherry = [Link]("cherry"); // true // Reducing
to a single value const numbers = [1, 2, 3, 4, 5]; const sum =
[Link]((acc, num) => acc + num, 0); // 15 // Slicing and splicing
const subset = [Link](1, 3); // ["banana","cherry"] (non-destructive)
[Link](1, 1); // Removes 1 item at index 1 (destructive)
13.7 Objects
// Object literal const person = { name: "Bob", city: "New Braunfels",
age: 35, isStudent: true, // Method (function as a property) greet() {
return `Hi, I'm ${[Link]} from ${[Link]}.`; // 'this' refers to the
object the method belongs to } }; // Accessing properties [Link];
// "Bob" — dot notation (preferred) person["city"]; // "New Braunfels" —
bracket notation (dynamic keys) // Adding / modifying / deleting [Link]
= "bob@[Link]"; // Add new property [Link] = 36; //
Modify existing delete [Link]; // Remove property //
Calling a method [Link](); // "Hi, I'm Bob from New Braunfels." //
Iterating object properties for (const key in person) { [Link](`${key}:
${person[key]}`); } // [Link](), [Link](), [Link]()
[Link](person) // ["name", "city", "age", "greet"]
[Link](person) // ["Bob", "New Braunfels", 36, [Function]]
[Link](person) // [["name","Bob"], ["city","New Braunfels"], ...]
13.8 Control Flow
// if / else if / else const score = 85; if (score >= 90)
{ [Link]("A"); } else if (score >= 80) { [Link]("B"); // This
runs } else if (score >= 70) { [Link]("C"); } else
{ [Link]("Below C"); } // Ternary operator (short if/else) const grade
= score >= 60 ? "Pass" : "Fail"; // "Pass" // switch (for multiple discrete
values) const day = "Wednesday"; switch (day) { case "Monday": case
"Tuesday": [Link]("Early week"); break; case "Wednesday":
[Link]("Midweek"); // This runs break; default:
[Link]("Other"); }
13.9 Loops
// for loop (when you know the count) for (let i = 0; i < 5; i++)
{ [Link](i); // 0, 1, 2, 3, 4 } // while loop (when condition-based)
let count = 0; while (count < 3) { [Link](count); count++; } //
for...of (iterate over iterable: array, string, NodeList) const fruits =
["apple", "banana", "cherry"]; for (const fruit of fruits)
{ [Link](fruit); } // for...in (iterate over object keys) const obj =
{ a: 1, b: 2, c: 3 }; for (const key in obj) { [Link](`${key}: $
{obj[key]}`); }
13.10 Functions
// Function Declaration (hoisted — can be called before definition) function
add(a, b) { return a + b; } // Function Expression (not hoisted) const
multiply = function(a, b) { return a * b; }; // Arrow Function (concise;
'this' is lexically scoped) const divide = (a, b) => a / b; // Implicit
return for single expressions const square = x => x * x; // Single
param: no parentheses needed const greet = (name) => { const msg = `Hello, $
{name}!`; // Multiple lines: use {} and explicit return return msg; }; //
Default parameters function createButton(text = "Click Me", color = "#2563eb")
{ return `<button style="background: ${color}">${text}</button>`; } // Rest
parameters (collect remaining args into an array) function sum(...numbers) {
return [Link]((total, n) => total + n, 0); } sum(1, 2, 3, 4, 5); // 15
// Immediately Invoked Function Expression (IIFE) (function() { // Runs
immediately; variables scoped inside })();
13.11 Quick Reference Checklist
● Use const by default; let only when reassignment needed; never var
● Always use === (strict equality), never ==
● Use template literals for string interpolation
● Use arrow functions for callbacks (.forEach, .map, .filter)
● Prefer .map() and .filter() over manual loops for arrays
● Add comments to explain why, not what — the code shows what
● Keep functions small and single-purpose
13.12 Practice Exercises
41. Tip Calculator: Write a function calculateTip(billAmount, tipPercent) that returns
the tip amount and the total. Test with calculateTip(45.50, 20) (should return tip: 9.10,
total: 54.60).
42. Quiz App: Create an array of 5 quiz question objects, each with question, answer, and
options properties. Write a function that checks a given answer against the correct one and
returns whether it is correct.
43. Array Manipulation: Given an array of 10 student objects with name and grade properties,
write code to: filter only students with grade >= 80, map them to get an array of just names, and
sort alphabetically.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 13: JavaScript Foundations
Section 14: JavaScript & the DOM
14.1 Overview
The DOM (Document Object Model) is the browser's in-memory representation of your HTML page as a
tree of objects. Every HTML element becomes a node in this tree, and JavaScript can read, modify,
create, and delete any node — instantly updating what the user sees without a page reload. This is what
makes modern interactive web applications possible.
When the browser parses your HTML, it builds the DOM tree. JavaScript accesses this tree through the
global document object. Think of document as the root of the entire page — it has methods to find
elements, create new ones, and listen for user interactions.
14.2 Selecting Elements
// querySelector: returns FIRST matching element (or null) const btn =
[Link]('#submit-btn'); // by ID const hero =
[Link]('.hero'); // by class const input =
[Link]('input[type="email"]'); // by attribute const firstLi =
[Link]('ul li'); // first li in ul // querySelectorAll:
returns ALL matching elements (NodeList) const allCards =
[Link]('.card'); // NodeList of all .card const allLinks
= [Link]('nav a'); // Iterate NodeList
[Link](card => { [Link] = '0.8'; }); // OLDER methods
(still valid) [Link]('main-title'); // by ID
(fastest) [Link]('card'); // HTMLCollection
(live) [Link]('p'); // HTMLCollection //
Always check for null before using const el =
[Link]('#optional-element'); if (el) { [Link] =
'Found it!'; }
14.3 Reading & Modifying Content
const heading = [Link]('h1'); // Reading content
[Link]; // Text only (safe — no HTML parsed) [Link];
// HTML content (can contain tags) // Setting content [Link] =
'New Heading Text'; // SAFE — text is not parsed as HTML [Link] =
'<em>Italic Heading</em>'; // Parses HTML (XSS risk if user input!) // Form
input values const input = [Link]('#email-input'); const value
= [Link]; // Read current value [Link] = 'bob@[Link]'; //
Set value // Attributes const img = [Link]('img');
[Link]('src'); // Read attribute [Link]('alt',
'Updated description'); // Set attribute [Link]('loading'); //
Remove attribute [Link]('src'); // Check if attribute
exists → true/false // Data attributes const card =
[Link]('[data-id]'); [Link]; // Reads data-
id attribute [Link]; // Reads data-category attribute
[Link] = '42'; // Sets data-id="42"
14.4 Changing Styles & Classes
const el = [Link]('.modal'); // Inline styles (use sparingly
— classList is better) [Link] = '#2563eb'; // camelCase
property names! [Link] = '1.5rem'; [Link] = 'none'; //
classList methods (PREFERRED approach)
[Link]('active'); // Adds class
[Link]('hidden'); // Removes class
[Link]('open'); // Adds if absent, removes if present
[Link]('active'); // Returns true/false
[Link]('old', 'new'); // Replace one class with another //
Why classList over inline styles? // 1. Styles stay in CSS (separation of
concerns) // 2. Classes are reusable // 3. CSS transitions and animations work
on class changes // 4. Much easier to maintain and read // Example: toggle
dark mode const toggle = [Link]('#dark-mode-btn');
[Link]('click', () =>
{ [Link]('dark-mode'); });
14.5 Creating & Removing Elements
// Creating elements const newItem = [Link]('li');
[Link] = 'New list item'; [Link]('task-item');
[Link]('data-id', '123'); // Adding to the DOM const list =
[Link]('#task-list'); [Link](newItem); // Add as
LAST child [Link](newItem); // Add as FIRST child // More
precise insertion const referenceEl = [Link]('#third-item');
[Link](newItem, referenceEl); // Insert before referenceEl //
Modern insertion methods [Link](newItem); // Insert newItem
before referenceEl [Link](newItem); // Insert newItem after
referenceEl // Removing elements [Link](); // Remove
from DOM (modern, clean) [Link](newItem); // Older method //
Cloning const clone = [Link](true); // true = deep clone (with
children) // innerHTML for batch insertion (be careful with user data!)
[Link] = ` <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> `; //
Replaces ALL children — use with care!
14.6 Event Handling
// addEventListener: the standard, preferred method const btn =
[Link]('#submit-btn'); [Link]('click',
function(event) { [Link](); // Prevent default browser
behavior (e.g., form submit) [Link]('Button clicked!');
[Link]([Link]); // The element that triggered the event
[Link]([Link]); // The element listener is attached
to }); // Arrow function syntax [Link]('click', (e) =>
{ [Link](); // Prevent event from bubbling up the DOM
tree }); // Common event types [Link]('click',
handler); // Mouse click [Link]('dblclick', handler); //
Double click [Link]('mouseover', handler); // Mouse enters
element [Link]('mouseout', handler); // Mouse leaves element
[Link]('keydown', handler); // Any key pressed (fires
repeatedly) [Link]('keyup', handler); // Key released
[Link]('input', handler); // Value changes (every keystroke)
[Link]('change', handler); // Value changes (on blur for
text) [Link]('focus', handler); // Input receives focus
[Link]('blur', handler); // Input loses focus
[Link]('submit', handler); // Form submitted
[Link]('scroll', handler); // Page scrolled
[Link]('resize', handler); // Window resized
[Link]('DOMContentLoaded', handler); // DOM fully
parsed // Removing event listeners function handleClick()
{ [Link]('clicked'); } [Link]('click', handleClick);
[Link]('click', handleClick); // Must pass same function
reference!
14.7 Event Delegation
// PROBLEM: Adding a listener to every list item is inefficient // (especially
when items are added dynamically) [Link]('li').forEach(li
=> { [Link]('click', handler); // ❌ Many listeners, breaks for
new items }); // SOLUTION: Event Delegation — one listener on the parent
const list = [Link]('#task-list');
[Link]('click', (event) => { // [Link] is the actual
element clicked (could be a child) if ([Link]('li'))
{ [Link]('completed'); } // Handle delete
button inside a list item if ([Link]('.delete-btn'))
{ [Link]('li').remove(); } }); // Benefits: // - One
listener instead of many // - Works for dynamically added items // - Better
performance
14.8 Annotated To-Do List Example
// HTML structure assumed: // <input id="task-input" type="text"
placeholder="Add a task..."> // <button id="add-btn">Add Task</button> // <ul
id="task-list"></ul> const input = [Link]('#task-input');
const addBtn = [Link]('#add-btn'); const list =
[Link]('#task-list'); // Add task function function addTask()
{ const text = [Link](); // Remove whitespace from ends if (!
text) return; // Guard clause: do nothing if input is empty // Create list
item const li = [Link]('li'); [Link] = ` <span
class="task-text">${text}</span> <button class="complete-btn" aria-
label="Mark complete">✓</button> <button class="delete-btn" aria-
label="Delete task">✕</button> `; [Link](li); // Add to list
[Link] = ''; // Clear input [Link](); // Return focus
to input } // Button click triggers add [Link]('click',
addTask); // Enter key also triggers add [Link]('keydown',
(e) => { if ([Link] === 'Enter') addTask(); }); // Event delegation for
complete and delete buttons [Link]('click', (e) => { if
([Link]('.complete-btn')) { // Toggle completed styling on the
li [Link]('li').[Link]('completed');
[Link]('li').querySelector('.task-text') .[Link]
= [Link]('li').[Link]('completed') ?
'line-through' : 'none'; } if ([Link]('.delete-btn')) {
[Link]('li').remove(); } });
14.9 Quick Reference Checklist
● Use querySelector / querySelectorAll (not getElementById)
● Use addEventListener, never inline onclick HTML attributes
● Use textContent for setting text (not innerHTML) when possible
● Check for null before operating on a queried element
● Use event delegation for dynamic lists
● Use [Link]/remove/toggle over inline style property
● Call [Link]() on form submits to handle with JS
● Remove event listeners when no longer needed to prevent memory leaks
14.10 Practice Exercises
44. Color Changer: Build a page with a button and 5 color swatches. Clicking a swatch changes the
page background color. Clicking the button resets to white. Use classList and a CSS class for
the active swatch.
45. Character Counter: Create a <textarea> with a maximum of 150 characters. Display a live
counter below showing characters remaining. When under 20, change the counter color to red
using a CSS class.
46. To-Do List: Build the full to-do list from the example above. Add: the ability to edit a task in-
place (double-click the text to make it editable), a count of remaining incomplete tasks, and a
"Clear completed" button.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 14: JavaScript & the DOM
Section 15: JavaScript — Modern Features & Async
15.1 Overview
ES6 (ECMAScript 2015) and subsequent yearly releases transformed JavaScript from a scripting language
into a powerful, modern programming language. This section covers the ES6+ features you will use
constantly in modern web development: destructuring, spread/rest, modules, Promises, async/await,
the Fetch API, and localStorage. Mastering these will allow you to write cleaner, more concise code and
work with real web APIs to display live data.
15.2 Destructuring
// Array destructuring const colors = ['red', 'green', 'blue']; const [first,
second, third] = colors; [Link](first); // "red" const
[primary, ...rest] = colors; [Link](rest); // ["green", "blue"] //
Swap variables without temp let a = 1, b = 2; [a, b] = [b, a]; // a=2, b=1 //
Object destructuring const user = { name: 'Bob', city: 'New Braunfels', age:
35 }; const { name, city } = user; // Extract specific properties // Rename
while destructuring const { name: userName, age: userAge } = user; // Default
values (if property is undefined) const { name: n, country = 'USA' } = user;
[Link](country); // "USA" (default, since user has no country) // Nested
destructuring const { address: { zip } = {} } = user; // Safe even if address
is undefined // Function parameter destructuring (very common in React!)
function greet({ name, city = 'Unknown' }) { return `Hello, ${name} from $
{city}!`; } greet(user); // "Hello, Bob from New Braunfels!"
15.3 Spread and Rest Operators
// SPREAD (...) — expand an iterable into individual elements // Spread in
arrays const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const combined =
[...arr1, ...arr2]; // [1,2,3,4,5,6] const copy = [...arr1]; // Shallow
copy // Spread in objects const defaults = { theme: 'light', lang: 'en' };
const userPrefs = { theme: 'dark', fontSize: 16 }; const finalPrefs =
{ ...defaults, ...userPrefs }; // later keys override earlier // { theme:
'dark', lang: 'en', fontSize: 16 } // Spread as function arguments const nums
= [3, 1, 4, 1, 5, 9]; [Link](...nums); // 9 // REST (...) — collect
remaining items into an array (opposite of spread) function sum(...numbers)
{ // rest parameter return [Link]((total, n) => total + n, 0); }
sum(1, 2, 3, 4, 5); // 15
15.4 ES Modules (import/export)
// === [Link] === // Named exports (can have multiple per file) export
function formatDate(date) { return new [Link]('en-
US').format(date); } export const TAX_RATE = 0.0825; // Texas sales tax! //
Default export (one per file) export default function calculateTotal(subtotal)
{ return subtotal * (1 + TAX_RATE); } // === [Link] === // Import named
exports import { formatDate, TAX_RATE } from './[Link]'; // Import default
export (name it anything) import calculateTotal from './[Link]'; // Import
all named exports as a namespace import * as Utils from './[Link]';
[Link](new Date()); // Dynamic import (lazy-load a module) const
{ formatDate } = await import('./[Link]'); // HTML: Must add type="module"
to script tag // <script type="module" src="js/[Link]"></script>
15.5 Promises
// A Promise represents a value that will be available in the future //
States: pending → fulfilled OR rejected const myPromise = new
Promise((resolve, reject) => { setTimeout(() => { const success = true;
if (success) { resolve("Data loaded!"); // Fulfill the promise }
else { reject(new Error("Load failed")); // Reject the
promise } }, 1000); }); // Consuming a Promise myPromise .then(data
=> [Link](data)) // Runs on resolve .catch(err =>
[Link](err)) // Runs on reject .finally(() =>
[Link]('Done')) // Always runs // [Link] — run multiple promises in
parallel [Link]([ fetch('/api/users'), fetch('/api/posts'),
fetch('/api/comments') ]).then(([users, posts, comments]) => { // All three
resolved }); // [Link] — even if some reject, get all results //
[Link] — resolves/rejects with the FIRST settled promise
15.6 Async / Await
// async/await is syntactic sugar over Promises — cleaner, reads like
synchronous code async function loadUserData(userId) { try { const
response = await fetch(`/api/users/${userId}`); // await pauses execution
until Promise resolves if (![Link]) { throw new Error(`HTTP
error! Status: ${[Link]}`); } const user = await
[Link](); // Parse JSON response return user; } catch (error) {
// Handles both network errors and thrown errors [Link]('Failed to
load user:', error); return null; // Return fallback value } finally {
// Runs whether or not an error occurred hideLoadingSpinner(); } } //
Call the async function async function init() { const user = await
loadUserData(42); if (user)
{ [Link]('#name').textContent = [Link]; } } //
Multiple awaits in parallel (don't do them sequentially if independent!) async
function loadAll() { // Sequential (slow — each waits for the previous)
const user = await fetchUser(); const posts = await fetchPosts(); // Doesn't
start until user finishes // Parallel (fast — both start simultaneously)
const [user2, posts2] = await [Link]([fetchUser(), fetchPosts()]); }
init();
15.7 Fetch API
// Basic GET request async function getWeather(city) { try { const
response = await fetch( `[Link]
latitude=29.70&longitude=-98.12` // Approximate coordinates for New
Braunfels, TX ); if (![Link]) { throw new Error(`Network
response was not ok: ${[Link]}`); } const data = await
[Link](); [Link](data); return data; } catch (error) {
[Link]('Fetch error:', error); } } // POST request (sending data)
async function createPost(postData) { const response = await
fetch('[Link] { method: 'POST',
headers: { 'Content-Type': 'application/json', }, body:
[Link](postData), // Convert object to JSON string }); const
newPost = await [Link](); return newPost; } // Displaying fetched
data in the DOM async function loadAndDisplayQuote() { const quoteEl =
[Link]('#quote'); const authorEl =
[Link]('#author'); [Link] = 'Loading...'; //
Show loading state try { const response = await
fetch('[Link] const data = await
[Link](); [Link] = `"${[Link]}"`;
[Link] = `— ${[Link]}`; } catch (err)
{ [Link] = 'Could not load quote. Check your connection.';
[Link](err); } }
15.8 localStorage
// localStorage: persists data in the browser across sessions // Key-value
store; values must be strings // Storing data
[Link]('username', 'Bob'); [Link]('theme',
'dark'); // Retrieving data const username =
[Link]('username'); // "Bob" const theme =
[Link]('theme'); // "dark" // Removing data
[Link]('theme'); // Clear all localStorage for this domain
[Link](); // Objects must be serialized with JSON const tasks = [
{ id: 1, text: 'Learn HTML', done: true }, { id: 2, text: 'Learn CSS',
done: true }, { id: 3, text: 'Learn JS', done: false } ]; // Saving
[Link]('tasks', [Link](tasks)); // Loading const
savedTasks = [Link]([Link]('tasks')) || []; // The || []
provides a fallback if nothing is saved yet // Pattern: Load on startup, save
on change function saveTasks() { [Link]('tasks',
[Link](tasks)); } // Call saveTasks() every time the task list
changes
15.9 Error Handling
// try / catch / finally try { const data = [Link](userInput); // Might
throw SyntaxError processData(data); } catch (error) { if (error
instanceof SyntaxError) { showError('Invalid JSON format'); } else {
[Link]('Unexpected error:', error); } } finally
{ hideLoadingState(); // Always runs } // Throwing custom errors function
divide(a, b) { if (b === 0) throw new Error('Cannot divide by zero');
return a / b; } // Console methods for debugging [Link]('Normal info');
// General output [Link]('Possible issue'); // Yellow warning
[Link]('Something broke'); // Red error with stack trace
[Link]([{name:'Bob',age:35}]); // Formatted table [Link]('Group
label'); [Link]('Inside group'); [Link]();
[Link]('timer'); // Code to measure [Link]('timer');
// Logs elapsed time
15.10 Quick Reference Checklist
● Always handle Promise rejections — unhandled rejections can crash the app
● Use async/await with try/catch instead of .then/.catch chains
● Check [Link] before parsing JSON from fetch()
● Use [Link]() and [Link]() for localStorage objects
● Provide fallback for [Link]() that returns null
● Use [Link]() for parallel, independent async operations
● Never use eval() — it is a major security vulnerability
● Add type="module" to script tag when using ES module imports
15.11 Practice Exercises
47. Public API: Fetch data from [Link]/posts and display the first 10 posts
as cards on a page. Each card shows the post title and body. Add a loading state while fetching
and an error state if the fetch fails.
48. Persistent To-Do: Extend the to-do list from Section 14 to save to localStorage on every change
and load from localStorage on page load. Verify by adding tasks, refreshing the page, and
confirming they persist.
49. Refactor: Take callback-based code (setTimeout nesting) and refactor it to use async/await.
Then refactor a sequential await chain of independent fetches to use [Link]() for
better performance.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 15: JavaScript — Modern Features & Async
Section 16: CSS Preprocessors & Build Tools
(Overview)
16.1 Overview
As projects grow in complexity, plain HTML, CSS, and JS become harder to manage. Build tools,
preprocessors, and version control systems address this complexity — automating repetitive tasks,
enabling modular code organization, and providing a professional development workflow. This section
provides a practical introduction to the tools Bob will encounter in real-world web development
projects.
16.2 Sass / SCSS
Sass (Syntactically Awesome Style Sheets) is a CSS preprocessor — a language that compiles down to
regular CSS. SCSS is the most popular Sass syntax (CSS-compatible with Sass features). Benefits:
variables, nesting, partials, mixins, and mathematical operations that go beyond what CSS alone offers
(though modern CSS variables have closed this gap considerably).
// === _variables.scss (a partial — file name starts with _) === $primary:
#2563eb; $font-size: 16px; // === _button.scss === .button { background:
$primary; font-size: $font-size; // Nesting (compiles to .button:hover)
&:hover { background: darken($primary, 10%); // Sass built-in function }
// Nesting for modifiers (compiles to .button--large) &--large
{ padding: 1rem 2rem; font-size: 1.25rem; } } // Mixin: reusable
blocks of CSS @mixin flex-center { display: flex; justify-content: center;
align-items: center; } .hero { @include flex-center; min-height: 100vh; }
// Extend: inherit styles from another selector %card-base { background:
#ffffff; padding: 1.5rem; border: 1px solid #e5e7eb; } .product-card
{ @extend %card-base; border-top: 4px solid $primary; } // ===
[Link] (main file — imports partials) === @use 'variables'; @use
'button'; // Compiles to a single [Link] file
16.3 npm and [Link]
[Link] is a JavaScript runtime that runs JS outside the browser — on your computer or a server. npm
(Node Package Manager) is Node's package registry with millions of open-source packages you can
install with a single command.
// Check if Node and npm are installed node --version // e.g., v22.0.0 npm
--version // e.g., 10.0.0 // Download from: [Link] (LTS version
recommended) // Initialize a new project (creates [Link]) npm init -y
// -y accepts all defaults // [Link] structure: { "name": "my-
project", "version": "1.0.0", "scripts": { "dev":
"vite", // Start dev server "build": "vite build", // Build
for production "preview": "vite preview" // Preview production build },
"devDependencies": { "vite": "^5.0.0" } } // Installing packages npm
install vite --save-dev // Install as dev dependency npm install lodash
// Install as regular dependency npm install // Install all
packages listed in [Link] // NEVER commit node_modules to Git — it can
contain thousands of files! // Use .gitignore (see 16.5)
16.4 Vite — Modern Build Tool
Vite (pronounced "veet" — French for "fast") is a next-generation build tool. It provides an instant
development server with Hot Module Replacement (HMR) — changes appear in the browser in
milliseconds without a full page reload. For production, it bundles and optimizes your code using Rollup.
// Create a new Vite project npm create vite@latest my-project -- --template
vanilla cd my-project npm install npm run dev // Starts dev server at
[Link] // Or for VS Code terminal: // 1. Open VS Code
integrated terminal (Ctrl+`) // 2. Navigate to desired folder: cd Desktop //
3. Run: npm create vite@latest my-site -- --template vanilla // 4. cd my-
site // 5. npm install // 6. npm run dev // 7. Open browser at
[Link] // Vite project structure my-project/ ├── [Link]
← Entry point ├── [Link] ← JavaScript entry (imports modules) ├──
[Link] ← Main CSS ├── public/ ← Static assets (not
processed by Vite) │ └── [Link] ├── [Link] └── [Link]
← Vite configuration (optional)
💡 TIP: Why Vite over Live Server?
Live Server (VS Code extension) is great for simple HTML/CSS/JS files. But once you use ES modules
(import/export), a real Vite dev server is needed because browsers require a server context for
modules. Vite also handles TypeScript, Sass, JSX, and more out of the box with near-zero
configuration.
16.5 Git & GitHub Basics
// Initialize a git repository git init // Check status (what files have
changed) git status // Stage files for commit (track changes) git add
[Link] // Specific file git add css/[Link] git add .
// ALL changed files // Commit with a meaningful message git commit -m "Add
hero section with Flexbox layout" // Good commit messages: verb + what changed
+ optional why // View commit history git log git log --oneline
// Compact view // Branching (work on features without affecting main code)
git branch feature-nav // Create branch git checkout feature-nav
// Switch to branch git checkout -b feature-footer // Create AND switch
(shorthand) // Merge branch back to main git checkout main git merge feature-
nav // === .gitignore file === // Create this file in your project root:
node_modules/ # Never commit (huge, regenerable) .DS_Store
# macOS system file dist/ # Build output (regenerable) .env
# Environment variables (secrets!) *.log # Log files //
GitHub: After creating a repo on [Link] git remote add origin
[Link] git branch -M main git push -u origin
main // First push git push // Subsequent
pushes
16.6 Browser DevTools Deep Dive
Panel Key Feature How to Use
Elements Grid/Flex inspector overlays Click the grid/flex badge next to an
element to see visual track/area
overlays
Console Live JavaScript execution Type any JS expression and press
Enter; perfect for quick testing
Network Waterfall timing chart Shows what loaded and when;
identify render-blocking resources
Network Throttling Simulate 3G/4G connections to
test performance on slow
networks
Sources Breakpoints Click line numbers to set
breakpoints; Step through code
with F10/F11
Performance Flame chart Record page activity; identify long
tasks that block the main thread
Lighthouse Automated audit Run for Performance, Accessibility,
Best Practices, SEO scores (0-100)
Application localStorage viewer View, edit, delete
localStorage/sessionStorage/cooki
es for your site
16.7 Quick Reference Checklist
● .gitignore file created with node_modules/ and dist/ listed
● Git initialized and at least 3 commits made with meaningful messages
● Vite dev server tested and working (npm run dev)
● [Link] LTS version installed (node --version)
● Lighthouse accessibility score above 90 before deployment
● Network panel checked — no unnecessary large files loading
● Commit often: treat commits like save points in a video game
16.8 Practice Exercises
50. Git Repository: Initialize a Git repository for one of your existing projects. Add a .gitignore,
make an initial commit, then make 3 more commits (each with a specific change and meaningful
message). Run git log --oneline to verify.
51. Vite Project: Create a new Vite project. Move your HTML/CSS/JS files in, run npm run dev, and
confirm everything loads. Then run npm run build and examine the dist/ folder — notice
how JS is bundled and minified.
52. Network Panel Analysis: Open any website in Chrome and go to the Network panel. Reload the
page. Answer: How many total requests were made? What was the total transfer size? Which
file took the longest to load? Is there any render-blocking resource?
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 16: CSS Preprocessors & Build Tools
Section 17: Putting It All Together — Project
Workflow
17.1 Overview
Knowing HTML, CSS, and JavaScript in isolation is one thing; building a complete, well-organized website
from scratch requires a disciplined workflow. Professional developers follow a structured process —
from planning through deployment — that keeps projects on track and produces maintainable code.
This section walks through every step of that process and concludes with a comprehensive project
checklist and a capstone project.
17.2 Step 1: Planning
Before writing a single line of code, plan the project thoroughly. Time spent planning prevents rework.
● Define the purpose: What problem does this site solve? Who is the audience?
● Content outline: List every page and the content each page contains.
● Wireframes: Sketch rough layouts for each page (paper or tools like Figma, Excalidraw). Focus
on layout, not visual design yet.
● Color palette: Choose 2–3 primary colors and define them as CSS variables before writing any
CSS.
● Typography: Select 1–2 fonts (Google Fonts or system fonts). Define base sizes, heading sizes,
and line heights.
● Assets: Gather and optimize all images and icons before development begins.
17.3 Step 2: File Structure
portfolio/ ├── [Link] ← Home page ├── [Link] ←
About page ├── [Link] ← Projects page ├── .gitignore ├── css/ │
├── [Link] ← Main stylesheet │ └── [Link] ← CSS reset
(optional) ├── js/ │ └── [Link] ← Main JavaScript └── images/
├── [Link] ├── [Link] └── [Link]
17.4 Step 3: HTML First
Write all semantic HTML markup before adding any CSS. This forces you to think about content structure
and accessibility from the start.
● Build the complete HTML skeleton: doctype, head, body structure.
● Add all semantic elements: header, nav, main, sections, articles, footer.
● Add all content: headings, paragraphs, lists, images (with alt text), forms.
● Validate with the W3C Validator before proceeding.
<!-- Start with structure, no classes needed yet --> <body> <header> <a
href="/" class="logo">Bob</a> <nav>...</nav> </header> <main>
<section class="hero"> <h1>Web Designer & Developer</h1> <p>Based
in New Braunfels, TX</p> <a href="#projects">View My Work</a>
</section> <section id="projects">...</section> <section
id="about">...</section> </main> <footer>...</footer> </body>
17.5 Step 4: CSS — Mobile First
53. Write a CSS reset / normalize at the top.
54. Define CSS custom properties in :root.
55. Apply base styles: typography, colors, body defaults.
56. Build mobile layout first (single-column).
57. Add Flexbox/Grid for component layouts.
58. Add media queries for tablet (768px) and desktop (1024px).
59. Add visual polish: transitions, hover effects, shadows.
/* === 1. Reset === */ *, *::before, *::after { box-sizing: border-box;
margin: 0; padding: 0; } img { max-width: 100%; height: auto; display:
block; } /* === 2. Custom Properties === */ :root { --primary: #2563eb;
--text: #1a1a1a; --bg: #ffffff; --spacing-sm: 0.5rem; --spacing-md:
1rem; --spacing-lg: 2rem; } /* === 3. Base Typography === */ body { font-
family: system-ui, sans-serif; font-size: 1rem; line-height: 1.6; color:
var(--text); } h1, h2, h3 { line-height: 1.2; } a { color: var(--primary);
text-decoration: none; } /* === 4. Mobile Layout === */ .navbar { padding:
var(--spacing-md); } .hero { padding: var(--spacing-lg) var(--spacing-md);
text-align: center; } .projects-grid { display: grid; gap: var(--spacing-
md); } /* === 5. Tablet === */ @media (min-width: 768px) { .projects-grid {
grid-template-columns: repeat(2, 1fr); } } /* === 6. Desktop === */ @media
(min-width: 1024px) { .projects-grid { grid-template-columns: repeat(3,
1fr); } .hero { padding: 5rem 2rem; } }
17.6 Step 5: JavaScript — Progressive Enhancement
Add interactivity last — the page should already look and work well without JavaScript. JavaScript
enhances the experience but should not be required for basic content access.
● Hamburger menu toggle for mobile navigation.
● Smooth scrolling for anchor links.
● Form validation and feedback.
● Any data fetching or dynamic content.
● Animations triggered on scroll (IntersectionObserver).
// Progressive enhancement: check if element exists before using const
hamburger = [Link]('.hamburger'); const navLinks =
[Link]('.nav-links'); if (hamburger && navLinks)
{ [Link]('click', () => { const isOpen =
[Link]('open'); [Link]('aria-expanded',
isOpen); }); } // Smooth scroll for anchor links
[Link]('a[href^="#"]').forEach(link =>
{ [Link]('click', (e) => { const target =
[Link]([Link]('href')); if (target)
{ [Link](); [Link]({ behavior: 'smooth',
block: 'start' }); } }); }); // Fade-in animation on scroll using
IntersectionObserver const observer = new IntersectionObserver((entries) => {
[Link](entry => { if ([Link])
{ [Link]('visible'); } }); }, { threshold: 0.1
}); [Link]('.fade-in').forEach(el =>
[Link](el));
17.7 Step 6: Accessibility Audit
● Run axe DevTools extension — fix all violations before proceeding.
● Keyboard test: Tab through the entire page. Every interactive element must be reachable.
● Check all color contrast ratios with DevTools color picker or WebAIM Contrast Checker.
● Verify all images have appropriate alt text.
● Confirm all form inputs have visible, associated labels.
● Test with screen reader (NVDA on Windows) on at least the home page.
17.8 Step 7: Performance Check
● Run Lighthouse audit (DevTools → Lighthouse tab). Target: Performance ≥ 90, Accessibility =
100.
● Check Network panel for oversized images — compress any over 200KB.
● Ensure all images have loading="lazy" (except hero/above-the-fold images).
● Check that CSS and JS files are not render-blocking (use defer on scripts).
● Use WebP format for all photography.
● Minimize HTTP requests: combine CSS files; avoid too many Google Font weights.
17.9 Step 8: Deployment
For static websites (HTML/CSS/JS with no server-side processing), the two easiest deployment options
are:
Platform Method Best For Cost
Netlify Drag-and-drop your Any static site; easiest Free tier available
project folder, or option; free HTTPS and
connect GitHub for auto- CDN
deploy
GitHub Pages Push to a GitHub repo; Developer portfolios; Free
enable Pages in repo open-source project sites
Settings
Vercel Connect GitHub; auto- Vite projects; fast CDN; Free tier available
deploys on every push great free tier
// Netlify drag-and-drop (no account needed for first deploy): // 1. Run: npm
run build (creates dist/ folder) // 2. Go to: [Link]/drop // 3. Drag
the dist/ folder onto the drop zone // 4. Your site is live with a
free .[Link] domain instantly! // GitHub Pages (for projects without a
build step): // 1. Push your code to GitHub // 2. Go to repo → Settings →
Pages // 3. Source: Deploy from branch → main → / (root) // 4. Save — site is
live at: [Link]/repo-name
17.10 Comprehensive 30-Point Project Checklist
HTML
● Valid HTML5 DOCTYPE on every page
● lang attribute on <html> element
● Descriptive, unique <title> on every page (50-60 chars)
● Viewport meta tag present on every page
● Semantic structural elements used (header, nav, main, footer)
● Heading hierarchy correct — single h1, no skipped levels
● All images have meaningful alt text
● All form inputs have associated <label> elements
● W3C Validator: zero errors on all pages
CSS
● box-sizing: border-box applied universally
● CSS custom properties defined in :root
● External stylesheet used — no inline styles
● Mobile-first responsive CSS with min-width media queries
● Images have max-width: 100%; height: auto;
● Focus styles visible for keyboard navigation
● Transitions use transform and opacity (GPU-accelerated)
● prefers-reduced-motion media query respected
JavaScript
● const/let only — no var
● Script loaded with defer attribute
● All DOM queries checked for null before use
● Event listeners use addEventListener (not inline HTML events)
● All Promises and async functions have error handling
Accessibility
● axe DevTools: zero violations
● Keyboard navigation: all interactive elements reachable and operable
● Color contrast meets WCAG AA (4.5:1 body text)
● Skip navigation link present
Performance & SEO
● Lighthouse Performance score ≥ 90
● All images compressed and in WebP format
● Below-the-fold images use loading="lazy"
● Meta description on every page
● No broken links (test with browser DevTools Network tab)
17.11 Capstone Practice Project
Build a 3-Page Personal Portfolio Website
Apply everything from this guide to build a portfolio site showcasing your web design work. The site
should be clean, responsive, accessible, and deployable.
Page 1 — Home ([Link]):
● Hero section: your name, title ("Web Designer | New Braunfels, TX"), and a call-to-action button
linking to Projects.
● Skills section: a grid of skill cards (HTML, CSS, JavaScript, Responsive Design, Accessibility).
● Brief about blurb with a link to the About page.
Page 2 — About ([Link]):
● Your photo (optimized WebP with alt text), bio paragraph, and a list of tools you use.
● A timeline or list of learning milestones.
● A downloadable resume link (download attribute on anchor tag).
Page 3 — Projects ([Link]):
● A responsive CSS Grid gallery of 4–6 project cards.
● Each card: project screenshot, title, brief description, technologies used, and a "View Project"
link.
● A filter system using JavaScript to show/hide projects by category.
Global requirements across all pages:
● Consistent navigation with active page highlighted.
● Footer with copyright, year (auto-updated with JS), and social links.
● 100% Lighthouse Accessibility score.
● Lighthouse Performance ≥ 90 on mobile.
● Deployed to Netlify or GitHub Pages with a working public URL.
● Repository on GitHub with meaningful commit history (minimum 10 commits).
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Section 17: Putting It All Together
Appendix A: HTML Quick Reference Card
Document Structure
Element Description Key Attributes
<!DOCTYPE html> HTML5 document declaration —
<html> Root element lang
<head> Document metadata container —
<meta> Metadata charset, name, content,
viewport
<title> Page title (tab + SEO) —
<link> External resources rel, href, type
<script> JavaScript src, defer, async, type
<body> Page content —
Semantic Layout
Element Purpose
<header> Introductory content / site header
<nav> Primary navigation links
<main> Main content (one per page)
<article> Self-contained content (blog post, card)
<section> Thematic grouping with heading
<aside> Supplementary content / sidebar
<footer> Footer for page or section
Element Purpose
<figure> Self-contained media with optional caption
<figcaption> Caption for figure
<div> Generic block container (no semantic meaning)
<span> Generic inline container (no semantic meaning)
Text Content
Element Purpose Notes
<h1>–<h6> Headings (level 1–6) One h1 per page; do not skip levels
<p> Paragraph Block element
<strong> Strong importance Renders bold; semantic
<em> Stress emphasis Renders italic; semantic
<code> Inline code Monospace
<pre> Preformatted text block Preserves whitespace
<blockquote> Block quotation Use cite attribute for source URL
<abbr> Abbreviation Use title for full expansion
<mark> Highlighted text Search highlights
<time> Date/time datetime="2026-06-24"
<br> Line break Void element; use sparingly
<hr> Thematic break Void element
Lists
Element Purpose
<ul> Unordered list (bullets)
<ol> Ordered list (numbers)
<li> List item (child of ul or ol)
<dl> Description list
<dt> Description term
Element Purpose
<dd> Description detail
Links & Media
Element Key Attributes Notes
<a> href, target, rel, Use rel="noopener
download noreferrer" for external links
<img> src, alt, width, height, alt is required; always set
loading, decoding width/height
<picture> — Art direction; multiple source
formats
<source> srcset, media, type Child of picture or video/audio
<video> src, controls, autoplay, autoplay requires muted
muted, loop, poster,
preload
<svg> xmlns, viewBox, width, Vector graphics; use aria-hidden
height for decorative
Forms
Element / Attribute Purpose
<form> Form container — action, method
<label> Input label — for must match input id
<input type="text"> Single-line text field
<input type="email"> Email field with validation
<input type="password"> Password (masked input)
<input type="checkbox"> Multiple choice selection
<input type="radio"> Single choice (group by name)
<input type="date"> Date picker
<input type="range"> Slider (min, max, value)
<input type="color"> Color picker
<textarea> Multi-line text input (rows, cols)
Element / Attribute Purpose
<select> / <option> Dropdown menu
<button type="submit"> Submit form
<fieldset> / <legend> Group related fields with label
required Field must be filled
placeholder Hint text (not a substitute for label)
autocomplete Browser autofill hint ("email", "name")
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Appendix A: HTML Quick Reference
Appendix B: CSS Quick Reference Card
Most-Used CSS Properties
Property Example Values Description
color #2563eb, hsl(221,83%,53%) Text color
background-color #f3f4f6, transparent Background fill
background-image url('[Link]'), linear- Background image or gradient
gradient(...)
background-size cover, contain, 100% Image sizing within element
font-family 'Inter', system-ui, sans- Font stack
serif
font-size 1rem, 1.25rem, Text size
clamp(1rem,2vw,2rem)
font-weight 400, 600, 700, bold Text thickness
line-height 1.5, 1.6 (unitless) Vertical space between lines
letter-spacing 0.02em, -0.01em Space between characters
text-align left, center, right Horizontal text alignment
text-decoration none, underline, line- Text decoration line
Property Example Values Description
through
text-transform uppercase, lowercase, Case transformation
capitalize
margin 0 auto, 1rem, 1rem 2rem Outer spacing (clockwise: T R B L)
padding 0.5rem 1rem, 1.5rem Inner spacing
border 1px solid #e5e7eb Border shorthand: width style
color
border-radius 8px, 50%, 9999px Rounded corners
width / max-width 100%, 1200px, 65ch Element width
height / min-height auto, 100vh, 300px Element height
display block, flex, grid, none, Layout mode
inline-block
position static, relative, Positioning scheme
absolute, fixed, sticky
top/right/bottom/left 0, 50%, 1rem Offset for positioned elements
z-index 1, 10, 9999 Stacking order (higher = on top)
overflow visible, hidden, scroll, How overflowing content is
auto handled
opacity 0, 0.5, 1 Transparency (0 = invisible, 1 =
opaque)
box-shadow 0 4px 6px rgba(0,0,0,0.1) Element shadow
transform translateY(-4px), 2D/3D transformation
scale(1.05), rotate(45deg)
transition all 200ms ease, transform Animated property changes
300ms ease-out
cursor pointer, default, not- Mouse cursor style
allowed
Flexbox Cheat Sheet
Container Property Values Effect
display: flex — Activates Flexbox
flex-direction row | column | row-reverse | Main axis direction
column-reverse
justify-content flex-start | center | flex- Main axis alignment
Container Property Values Effect
end | space-between | space-
around | space-evenly
align-items flex-start | center | flex- Cross axis alignment
end | stretch | baseline
flex-wrap nowrap | wrap Whether items wrap to new line
gap 1rem, 1rem 2rem Space between items
Item Property Values Effect
flex 1 | 0 0 250px | 1 1 auto Shorthand for grow shrink basis
flex-grow 0 | positive number How much item grows to fill space
flex-shrink 1|0 Whether item shrinks when
cramped
flex-basis auto | 250px | 30% Item's starting size
align-self auto | center | flex-end Override cross-axis alignment for
one item
order 0 (default) | integer Visual order (lower = first)
CSS Grid Cheat Sheet
Container Property Example Effect
display: grid — Activates Grid
grid-template-columns repeat(3, 1fr), 250px 1fr Define column tracks
grid-template-rows auto 1fr auto Define row tracks
grid-template-areas "header header" "sidebar Named layout areas
main"
gap 1rem, 1rem 2rem Space between rows and columns
repeat(auto-fit, — Responsive columns without
minmax(250px,1fr)) media queries
place-items center Shorthand: align-items + justify-
items
Item Property Example Effect
grid-column 1 / 3, span 2 Column placement / span
grid-row 1 / 3, span 2 Row placement / span
grid-area header Place in named area
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Appendix B: CSS Quick Reference
Appendix C: JavaScript Quick Reference Card
Array Methods
Method Returns Mutates? Example
push(item) new length Yes [Link]('d')
pop() removed item Yes [Link]()
shift() removed item Yes [Link]()
unshift(item) new length Yes [Link]('a')
splice(i, n) removed items Yes [Link](1,2)
slice(start, end) new array No [Link](0,3)
concat(arr2) new array No [Link]([4,5])
map(fn) new array No [Link](x => x * 2)
filter(fn) new array No [Link](x => x >
3)
find(fn) first match or undefined No [Link](x => [Link]
=== 5)
findIndex(fn) index or -1 No [Link](x =>
x > 3)
includes(val) boolean No [Link]('a')
forEach(fn) undefined No [Link](x =>
[Link](x))
Method Returns Mutates? Example
reduce(fn, init) accumulated value No [Link]((acc,x)
=> acc+x, 0)
sort(fn) sorted array Yes [Link]((a,b) =>
a-b)
reverse() reversed array Yes [Link]()
join(sep) string No [Link](', ')
flat(depth) new array No [[1,2],[3]].flat()
some(fn) boolean No [Link](x => x >
5)
every(fn) boolean No [Link](x => x >
0)
String Methods
Method Returns Example
.length number 'hello'.length // 5
.toUpperCase() string 'hi'.toUpperCase() // 'HI'
.toLowerCase() string 'HI'.toLowerCase() // 'hi'
.trim() string ' hi '.trim() // 'hi'
.trimStart() / .trimEnd() string Trim one side only
.includes(str) boolean 'hello'.includes('ell') //
true
.startsWith(str) boolean 'hello'.startsWith('he') /
/ true
.endsWith(str) boolean 'hello'.endsWith('lo') //
true
.indexOf(str) index or -1 'hello'.indexOf('l') // 2
.slice(start, end) string 'hello'.slice(1,3) // 'el'
.replace(old, new) string 'hi
bob'.replace('bob','Bob')
.replaceAll(old, new) string Replace all occurrences
.split(sep) array 'a,b,c'.split(',') //
['a','b','c']
.padStart(len, char) string '5'.padStart(3,'0') //
'005'
.repeat(n) string 'ab'.repeat(3) // 'ababab'
Method Returns Example
.charAt(i) string 'hi'.charAt(0) // 'h'
DOM Methods
Method / Property Description
[Link](sel) First matching element (or null)
[Link](sel) All matching elements (NodeList)
[Link] Get/set text content (safe)
[Link] Get/set HTML content (XSS risk with user data)
[Link] Get/set form input value
[Link](name) Read attribute value
[Link](name, val) Set attribute value
[Link](name) Remove an attribute
[Link](cls) Add CSS class
[Link](cls) Remove CSS class
[Link](cls) Add if absent; remove if present
[Link](cls) Returns boolean
[Link](tag) Create a new element node
[Link](child) Add child as last child of parent
[Link](child) Add child as first child of parent
[Link]() Remove element from DOM
[Link](sel) Find nearest ancestor matching selector
[Link](sel) Returns true if element matches selector
[Link](evt, fn) Attach event listener
[Link](evt, fn) Detach event listener
[Link]() Prevent default browser behavior
[Link]() Stop event bubbling up DOM
[Link] Element that triggered the event
Common Event Types
Event Fires When Common Target
click Element is clicked Buttons, links, any element
dblclick Element is double-clicked Any element
input Value changes (every keystroke) input, textarea
change Value committed (on blur) select, checkbox, radio
submit Form is submitted form
keydown Key is pressed down input, document
keyup Key is released input, document
focus Element gains focus input, button, a
blur Element loses focus input, button, a
mouseover Mouse enters element Any element
mouseout Mouse leaves element Any element
scroll Page or element is scrolled window, element
resize Window is resized window
DOMContentLoaded HTML fully parsed (before document
images/CSS)
load Everything (images, CSS) fully window
loaded
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Appendix C: JavaScript Quick Reference
Appendix D: VS Code Keyboard Shortcuts
(Windows)
Editing
Shortcut Action
Ctrl+C / Ctrl+X / Ctrl+V Copy / Cut / Paste
Ctrl+Z / Ctrl+Shift+Z Undo / Redo
Ctrl+/ Toggle line comment
Shift+Alt+A Toggle block comment
Alt+↑ / Alt+↓ Move line up / down
Shift+Alt+↑ / ↓ Copy line up / down
Ctrl+Shift+K Delete current line
Ctrl+Enter Insert line below (without moving cursor)
Ctrl+Shift+Enter Insert line above
Ctrl+] Indent line
Ctrl+[ Outdent line
Alt+Shift+F Format document (runs Prettier)
Ctrl+K Ctrl+F Format selection
Ctrl+D Add selection to next find match (multi-cursor)
Ctrl+Shift+L Select all occurrences of current selection
Alt+Click Add cursor at clicked position (multi-cursor)
Ctrl+U Undo last cursor operation
Shift+Alt+I Add cursor to end of each selected line
Navigation
Shortcut Action
Ctrl+P Quick Open — find and open any file
Ctrl+Shift+P Command Palette — all VS Code commands
Ctrl+G Go to line number
Ctrl+F Find in current file
Ctrl+H Find and replace in current file
Shortcut Action
Ctrl+Shift+F Find across all files
Ctrl+Shift+H Replace across all files
Alt+← / Alt+→ Go back / forward (navigation history)
Ctrl+Home / Ctrl+End Jump to top / bottom of file
Ctrl+Tab Switch between open editor tabs
Ctrl+W Close current editor tab
F12 Go to definition
Shift+F12 Find all references
F2 Rename symbol everywhere
Panels & Interface
Shortcut Action
Ctrl+` Toggle integrated terminal
Ctrl+Shift+` Create new terminal
Ctrl+B Toggle sidebar visibility
Ctrl+Shift+E Focus Explorer panel
Ctrl+Shift+X Open Extensions panel
Ctrl+Shift+G Open Source Control (Git) panel
Ctrl+K Z Zen Mode (distraction-free fullscreen)
Ctrl+, Open Settings
Ctrl+Shift+I Toggle browser DevTools (in browser, not VS Code)
Emmet Shortcuts (HTML)
Emmet is built into VS Code and lets you expand abbreviations into full HTML. Type the abbreviation and
press Tab:
Type This + Tab Expands To
! Full HTML5 boilerplate
Type This + Tab Expands To
[Link] <div class="container"></div>
ul>li*5 <ul> with 5 <li> children
header+main+footer header, main, footer as siblings
a[href="#"] <a href="#"></a>
input:email <input type="email">
form>(label+input)*3 Form with 3 label+input pairs
p{Hello World} <p>Hello World</p>
img[src="" alt=""] img with src and alt attributes
.[Link] <div class="card featured"></div>
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Appendix D: VS Code Keyboard Shortcuts
Appendix E: Recommended Resources
Primary References (Bookmark These First)
Resource URL Best For
MDN Web Docs [Link] The authoritative reference for
HTML, CSS, and JavaScript. Every
element, property, and method
documented with browser
compatibility. Your first stop for
any question.
Can I Use [Link] Browser compatibility tables for
every CSS and HTML feature.
Before using a new feature, check
if it is supported in your target
browsers.
W3C Validator [Link] Validate your HTML for errors and
warnings. Run this on every page
before deployment.
Resource URL Best For
CSS Validator [Link]/css-validator Validate your CSS for syntax
errors.
Learning & Tutorials
Resource URL Best For
[Link] [Link] The best modern JavaScript
tutorial. Comprehensive, accurate,
and beautifully written. Covers
ES6+ thoroughly. Free online.
[Link] [Link] Google's official resource for web
performance, PWAs, and modern
best practices. Excellent articles on
Core Web Vitals, accessibility, and
SEO.
CSS-Tricks [Link] Extensive guides, tutorials, and the
famous Flexbox and Grid complete
guides. The almanac is a useful CSS
property reference.
Flexbox Guide [Link]/snippets/css/a- The most referenced Flexbox
guide-to-flexbox/ visual guide on the internet.
Bookmark it.
Grid Guide [Link]/snippets/css/ Same for CSS Grid —
complete-guide-grid/ comprehensive visual reference.
The Odin Project [Link] Free, project-based full-stack
curriculum. Excellent path for
structured learning with real
projects.
freeCodeCamp [Link] Free coding curriculum with
certifications. Good structured
practice problems. Large
community forum for help.
Accessibility Resources
Resource URL Best For
The A11Y Project [Link] Community-driven resource for
web accessibility. Practical
Resource URL Best For
checklist, patterns, and resources.
WebAIM [Link] Web accessibility in mind.
Excellent articles, contrast
checker, and WCAG quick
reference.
WCAG 2.1 Quick Reference [Link]/WAI/WCAG21/ Official W3C filterable reference to
quickref/ all WCAG success criteria.
axe DevTools [Link]/axe/devtools/ Browser extension for automated
accessibility testing. Install in
Chrome or Edge.
Tools & Utilities
Tool URL Purpose
Squoosh [Link] Free browser-based image
compression. Convert and
compress images to WebP/AVIF.
Google Fonts [Link] Free, open-source web fonts. Filter
by style, weight, and language
support.
Coolors [Link] Color palette generator. Generate,
save, and export color schemes for
your projects.
Figma [Link] Free browser-based design and
wireframing tool. Industry
standard for UI/UX design.
CodePen [Link] Online code editor for quick
HTML/CSS/JS experiments. Great
for sharing demos and exploring
others' work.
Regex101 [Link] Test and debug regular
expressions with explanations.
Essential for string pattern
matching in JavaScript.
JSON Placeholder [Link] Free fake REST API for testing and
prototyping Fetch API calls without
a real backend.
Open Meteo [Link] Free weather API with no API key
required. Great for API practice
projects. New Braunfels
Tool URL Purpose
coordinates: lat 29.70, lon -98.12.
Community & Help
Community URL Best For
Stack Overflow [Link] Q&A for programming questions.
Most questions have already been
asked and answered. Search
before asking.
freeCodeCamp Forum [Link] Beginner-friendly community for
asking questions about HTML, CSS,
and JavaScript.
Reddit r/webdev [Link]/r/webdev Active community for web
developers. News, project
feedback, career discussions.
Reddit r/learnwebdev [Link]/r/learnwebdev Beginner-focused subreddit. Post
your code for feedback; ask for
advice on learning paths.
💡 TIP: Your Recommended Learning Order
Work through this guide section by section. After completing each section, build a small project
applying that section's concepts before moving on. Suggested project sequence: (1) Static HTML
page → (2) Styled page with CSS → (3) Flexbox navigation + card grid → (4) Grid page layout → (5)
Responsive page → (6) Add JavaScript interactivity → (7) Fetch an API → (8) Full 3-page portfolio.
Return to this guide as a reference for every project.
End of Study Guide
Web Design Study Guide | Bob | New Braunfels, TX | 2026
HTML · CSS · JavaScript · Responsive Design · Accessibility
Keep building. Every expert was once a beginner.
Web Design Study Guide | Bob | New Braunfels, TX | 2026 | Appendix E: Recommended Resources