Chapter 15 Intermediate 58 Questions

Practice Questions — CSS Manipulation with JavaScript

← Back to Notes
9 Easy
14 Medium
8 Hard

Topic-Specific Questions

Question 1
Easy
What is logged?
<div id="box" style="color: red; font-size: 20px;">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.style.color);
console.log(box.style.fontSize);
</script>
element.style reads inline styles.
red
20px
Question 2
Easy
What is logged?
<style>#box { background-color: blue; width: 200px; }</style>
<div id="box">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.style.backgroundColor);
console.log(box.style.width);
</script>
element.style only reads inline styles, not styles from a stylesheet.
(empty string)
(empty string)
Question 3
Easy
What is logged?
<style>#box { background-color: blue; width: 200px; }</style>
<div id="box">Hello</div>

<script>
const computed = getComputedStyle(document.getElementById("box"));
console.log(computed.width);
console.log(computed.backgroundColor);
</script>
getComputedStyle reads the actual computed values from all CSS sources.
200px
rgb(0, 0, 255)
Question 4
Easy
What class does the div have after this code?
<div id="box" class="card">Hello</div>

<script>
const box = document.getElementById("box");
box.classList.replace("card", "panel");
console.log(box.className);
</script>
replace swaps one class for another.
panel
Question 5
Medium
What is logged?
<style>
  :root { --color: #a855f7; }
  #box { color: var(--color); }
</style>
<div id="box">Hello</div>

<script>
const root = document.documentElement;
const value = getComputedStyle(root).getPropertyValue("--color");
console.log(value.trim());

root.style.setProperty("--color", "#06b6d4");
const newValue = getComputedStyle(root).getPropertyValue("--color");
console.log(newValue.trim());
</script>
setProperty changes the CSS variable. getPropertyValue reads it.
#a855f7
#06b6d4
Question 6
Medium
What happens?
<style>
  .box { width: 100px; height: 100px; background: #a855f7; transition: all 0.5s; }
  .box.big { width: 300px; background: #06b6d4; }
</style>
<div class="box" id="box"></div>

<script>
document.getElementById("box").classList.add("big");
</script>
Adding the 'big' class changes width and background. The transition animates the change.
The box smoothly animates from 100px wide (purple) to 300px wide (teal) over 0.5 seconds.
Question 7
Medium
What is logged?
<div id="box" style="color: red;">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.style.cssText);
box.style.cssText = "background: blue; font-size: 20px;";
console.log(box.style.color);
console.log(box.style.backgroundColor);
console.log(box.style.fontSize);
</script>
cssText replaces ALL inline styles.
color: red;
(empty string)
blue
20px
Question 8
Medium
What is logged?
<div id="box" style="width: 200px;">Hello</div>

<script>
const box = document.getElementById("box");
box.style.width = "";
console.log(box.style.width);
console.log(box.getAttribute("style"));
</script>
Setting a style to empty string removes that inline style.
(empty string)
(empty string or null)
Question 9
Hard
What is logged?
<style>
  :root {
    --gap: 10px;
    --cols: 3;
  }
</style>

<script>
const root = document.documentElement;
console.log(getComputedStyle(root).getPropertyValue("--gap").trim());
console.log(getComputedStyle(root).getPropertyValue("--cols").trim());

root.style.setProperty("--cols", "4");
console.log(getComputedStyle(root).getPropertyValue("--cols").trim());

console.log(getComputedStyle(root).getPropertyValue("--missing").trim());
</script>
getPropertyValue returns empty string for undefined variables.
10px
3
4
(empty string)
Question 10
Hard
What is the color of the box text?
<style>
  #box { color: blue; }
  .highlight { color: green !important; }
</style>
<div id="box">Hello</div>

<script>
const box = document.getElementById("box");
box.style.color = "red"; // Inline style
box.classList.add("highlight"); // Has !important
</script>
!important overrides inline styles.
The text is green.
Question 11
Hard
What is logged?
<style>.box { width: 50%; padding: 1em; font-size: 20px; }</style>
<div class="box" id="box">Hello</div>

<script>
const computed = getComputedStyle(document.getElementById("box"));
console.log(typeof computed.width);
console.log(computed.width.endsWith("px"));
console.log(computed.padding.endsWith("px"));
</script>
getComputedStyle returns resolved values in px, not the original units.
string
true
true
Question 12
Easy
What does the box look like after this code?
<div id="box">Hello</div>

<script>
const box = document.getElementById("box");
box.style.padding = "20px";
box.style.backgroundColor = "#a855f7";
box.style.color = "white";
box.style.borderRadius = "12px";
</script>
Each line sets an inline CSS style.
A white text "Hello" on a purple (#a855f7) background with 20px padding and rounded corners (12px radius).
Question 13
Medium
What is logged?
<style>
  :root { --theme: light; --bg: white; }
</style>

<script>
const root = document.documentElement;
root.style.setProperty("--theme", "dark");
root.style.setProperty("--bg", "#1a1a2e");

console.log(getComputedStyle(root).getPropertyValue("--theme").trim());
console.log(getComputedStyle(root).getPropertyValue("--bg").trim());
</script>
setProperty overrides the CSS variable values.
dark
#1a1a2e
Question 14
Hard
What is logged?
<style>
  #box { transition: opacity 0.5s; opacity: 1; }
  #box.hidden { opacity: 0; }
</style>
<div id="box">Hello</div>

<script>
const box = document.getElementById("box");
box.classList.add("hidden");
console.log(getComputedStyle(box).opacity);
setTimeout(function() {
  console.log(box.classList.contains("hidden"));
}, 600);
</script>
The class is added immediately. The visual transition takes 0.5s but the computed value updates instantly.
0 (logged immediately)
true (logged after 600ms)
Question 15
Medium
What is logged?
<div id="box" style="width: 100px; height: 50px; background: red;"></div>

<script>
const box = document.getElementById("box");
console.log(box.style.width);
console.log(box.style.height);
box.style.width = "200px";
console.log(box.style.cssText);
</script>
style.cssText shows all inline styles as a string.
100px
50px
width: 200px; height: 50px; background: red;

Mixed & Application Questions

Question 1
Easy
What is logged?
<div id="box" class="card active">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.classList.length);
console.log(box.classList[0]);
console.log(box.classList[1]);
</script>
classList is array-like with indexed access.
2
card
active
Question 2
Medium
What is the value of --primary after this code?
<style>
  :root { --primary: red; }
  body { --primary: blue; }
</style>

<script>
const rootVal = getComputedStyle(document.documentElement).getPropertyValue("--primary").trim();
const bodyVal = getComputedStyle(document.body).getPropertyValue("--primary").trim();
console.log("root:", rootVal);
console.log("body:", bodyVal);
</script>
CSS variables can be overridden at different levels of the DOM.
root: red
body: blue
Question 3
Easy
What is the difference between element.style and getComputedStyle(element)?
One reads inline styles, the other reads all applied styles.
element.style reads and sets only inline styles (styles set directly on the element via the style attribute or JavaScript). getComputedStyle(element) reads the final computed styles from all CSS sources: inline styles, stylesheets, inherited styles, and browser defaults. getComputedStyle is read-only; you cannot set styles with it.
Question 4
Medium
Why is classList.toggle better than inline styles for a dark mode toggle?
Think about code organization and maintainability.
classList.toggle is better because: (1) All dark mode styles are defined in CSS, keeping style logic in one place. (2) One toggle call changes all properties at once instead of setting each one individually. (3) CSS transitions work automatically on class changes. (4) It is easier to debug -- you can see the class in DevTools. (5) You can define complex selectors like .dark .card, .dark .nav in CSS. With inline styles, you would need to set every property on every element manually.
Question 5
Medium
How do CSS custom properties (variables) make theme switching easy?
Think about what happens when you change a variable that is used in 50 places.
CSS variables are defined once (usually on :root) and referenced everywhere with var(--name). When JavaScript changes a variable with setProperty, every element using that variable updates automatically. For a theme switch, you change 4-5 variables (--bg, --text, --primary, etc.) and the entire site's color scheme updates instantly. Without variables, you would need to find and change every element individually.
Question 6
Medium
What is logged?
<style>
  .fade { opacity: 0; transition: opacity 0.5s; }
  .fade.show { opacity: 1; }
</style>
<div class="fade" id="box">Hello</div>

<script>
const box = document.getElementById("box");
console.log(getComputedStyle(box).opacity);
box.classList.add("show");
console.log(getComputedStyle(box).opacity);
</script>
Adding the class changes opacity immediately in the computed style.
0
1
Question 7
Hard
What is logged?
<style>
  :root { --size: 16px; }
  #box { font-size: var(--size); }
</style>
<div id="box">Hello</div>

<script>
const root = document.documentElement;
const box = document.getElementById("box");

console.log(getComputedStyle(box).fontSize);
root.style.setProperty("--size", "24px");
console.log(getComputedStyle(box).fontSize);
root.style.setProperty("--size", "2em");
console.log(getComputedStyle(box).fontSize);
</script>
CSS variables are applied as regular CSS values. em is relative to parent font-size.
16px
24px
32px
Question 8
Hard
What happens?
<style>
  .box { width: 100px; transition: width 1s; }
</style>
<div class="box" id="box" style="background: #a855f7; height: 50px;"></div>

<script>
const box = document.getElementById("box");
box.style.width = "100px"; // Same as current
box.style.width = "300px"; // Change
</script>
Both style changes happen in the same synchronous code block.
The box jumps directly to 300px without any animation.
Question 9
Medium
What is logged?
<script>
console.log(window.scrollY);
window.scrollTo(0, 500);
console.log(window.scrollY);
</script>

Assuming the page is long enough to scroll.

scrollTo changes the scroll position synchronously.
0
500
Question 10
Hard
What is logged?
<style>
  .card { color: blue; }
  .card.dark { color: white; background: #1a1a2e; }
</style>
<div class="card" id="card">Hello</div>

<script>
const card = document.getElementById("card");
console.log(getComputedStyle(card).color);
card.style.color = "red"; // Inline
console.log(getComputedStyle(card).color);
card.classList.add("dark"); // .card.dark says color: white
console.log(getComputedStyle(card).color);
</script>
Inline styles have higher specificity than class selectors.
rgb(0, 0, 255)
rgb(255, 0, 0)
rgb(255, 0, 0)
Question 11
Easy
What happens?
<style>
  .box { width: 100px; height: 100px; background: #a855f7; }
</style>
<div class="box" id="box"></div>

<script>
const box = document.getElementById("box");
box.style.background = "#06b6d4";
</script>
Inline styles override stylesheet styles.
The box changes from purple (#a855f7) to teal (#06b6d4). The inline style overrides the stylesheet.
Question 12
Medium
What is logged?
<style>
  #box { width: 50%; }
</style>
<div id="box" style="width:300px;">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.style.width);
console.log(getComputedStyle(box).width);
</script>
The inline style (300px) overrides the stylesheet (50%). element.style reads inline; getComputedStyle reads the final value.
300px
300px
Question 13
Easy
What is logged?
<div id="box" class="a b c">Hello</div>

<script>
const box = document.getElementById("box");
console.log(box.classList.length);
box.classList.remove("b");
console.log(box.className);
</script>
classList.length counts the classes. remove takes out one class.
3
a c
Question 14
Hard
What is logged?
<style>
  :root { --gap: 10; }
</style>

<script>
const root = document.documentElement;
const gap = getComputedStyle(root).getPropertyValue("--gap").trim();
console.log(gap);
console.log(typeof gap);
console.log(gap * 2);
</script>
CSS variable values are always returned as strings.
10
string
20
Question 15
Medium
What is the best way to create a hover effect: CSS :hover or JavaScript mouseenter/mouseleave?
Think about simplicity and performance.
For simple hover effects (color change, scale, shadow), CSS :hover is better -- it is simpler, more performant, and does not require JavaScript. Use JavaScript mouseenter/mouseleave only when you need complex logic (like fetching data on hover, showing different content based on state, or coordinating with other elements). Rule: use CSS when possible, JS when necessary.
Question 16
Medium
What is logged?
<div id="box" class="active">Hello</div>

<script>
const box = document.getElementById("box");
const result = box.classList.replace("active", "inactive");
console.log(result);
console.log(box.className);

const result2 = box.classList.replace("missing", "found");
console.log(result2);
console.log(box.className);
</script>
replace returns true if the replacement was made, false if the old class was not found.
true
inactive
false
inactive

Multiple Choice Questions

MCQ 1
How do you change the background color of an element with JavaScript?
  • A. element.bg = 'red'
  • B. element.style.backgroundColor = 'red'
  • C. element.setBackground('red')
  • D. element.css('background', 'red')
Answer: B
B is correct. element.style.backgroundColor is the correct property. CSS uses background-color (kebab-case), JavaScript uses backgroundColor (camelCase).
MCQ 2
What does getComputedStyle(element) return?
  • A. Only inline styles
  • B. Only stylesheet styles
  • C. The final computed styles from all CSS sources
  • D. CSS variable values only
Answer: C
C is correct. getComputedStyle returns the final, computed values from all sources: inline styles, stylesheets, inherited properties, and browser defaults.
MCQ 3
What does classList.toggle('dark') return?
  • A. undefined
  • B. The element
  • C. true if the class was added, false if removed
  • D. The class name
Answer: C
C is correct. toggle returns a boolean: true if the class was added (was missing), false if it was removed (was present).
MCQ 4
How do you set a CSS custom property with JavaScript?
  • A. document.style.setProperty('--color', 'red')
  • B. document.documentElement.style.setProperty('--color', 'red')
  • C. document.css('--color', 'red')
  • D. root.setVariable('--color', 'red')
Answer: B
B is correct. document.documentElement is the html element where :root variables live. style.setProperty('--color', 'red') sets the CSS variable.
MCQ 5
Why does element.style.width return empty string when width is set in a stylesheet?
  • A. It is a bug
  • B. element.style only reads inline styles, not stylesheet styles
  • C. Width is not a valid CSS property
  • D. The element must be visible first
Answer: B
B is correct. element.style is the inline style object. It only contains properties set directly on the element's style attribute, not properties from external or internal stylesheets.
MCQ 6
What format does getComputedStyle return colors in?
  • A. Hex (#ff0000)
  • B. Named color (red)
  • C. RGB (rgb(255, 0, 0))
  • D. HSL (hsl(0, 100%, 50%))
Answer: C
C is correct. Computed values for colors are returned in rgb(r, g, b) format (or rgba if transparent). Even if you defined the color as hex, named, or HSL, the computed value is always RGB.
MCQ 7
Which CSS property CANNOT be animated with transitions?
  • A. opacity
  • B. transform
  • C. display
  • D. background-color
Answer: C
C is correct. display is a discrete property (none/block/flex etc.) that cannot be smoothly animated. Use opacity + visibility instead for show/hide animations.
MCQ 8
What is window.scrollY?
  • A. The width of the scrollbar
  • B. The number of pixels scrolled vertically from the top
  • C. The total height of the page
  • D. The viewport height
Answer: B
B is correct. window.scrollY returns the number of pixels the page has been scrolled vertically from the top. At the top of the page, it is 0.
MCQ 9
What does style.cssText = 'color: red;' do?
  • A. Adds color: red to existing inline styles
  • B. Replaces ALL inline styles with only color: red
  • C. Sets a CSS class
  • D. Has no effect
Answer: B
B is correct. cssText replaces the entire inline style attribute with the new string. Any previously set inline styles are lost.
MCQ 10
In terms of CSS specificity, what is the order from lowest to highest?
  • A. Inline > Class > ID > Element
  • B. Element > Class > ID > Inline
  • C. ID > Class > Inline > Element
  • D. Class > Element > Inline > ID
Answer: B
B is correct. Specificity from lowest to highest: element selectors (p, div) < class selectors (.card) < ID selectors (#main) < inline styles. !important overrides all of these.
MCQ 11
Which method replaces one CSS class with another?
  • A. classList.swap('old', 'new')
  • B. classList.replace('old', 'new')
  • C. classList.change('old', 'new')
  • D. classList.switch('old', 'new')
Answer: B
B is correct. classList.replace('old', 'new') removes the old class and adds the new one in a single operation. Returns true if the replacement was made.
MCQ 12
What is document.documentElement?
  • A. The body element
  • B. The head element
  • C. The html element (root of the DOM)
  • D. The document object
Answer: C
C is correct. document.documentElement returns the root element of the document, which is the <html> element. This is where :root CSS variables are typically defined.
MCQ 13
Why does an inline style override a stylesheet class with the same property?
  • A. Inline styles load first
  • B. Inline styles have higher specificity than class or ID selectors
  • C. Classes are ignored when inline styles exist
  • D. It is a browser rendering quirk
Answer: B
B is correct. In CSS specificity, inline styles (style attribute) have a specificity of 1000, which is higher than any selector in a stylesheet (IDs = 100, classes = 10, elements = 1). Only !important can override inline styles.
MCQ 14
How do you smoothly scroll to the top of the page?
  • A. window.scrollTo(0, 0)
  • B. window.scrollTo({ top: 0, behavior: 'smooth' })
  • C. document.body.scrollTop = 0
  • D. window.scroll('top')
Answer: B
B is correct. Passing an object with behavior: 'smooth' makes the scroll animated instead of instant. Option A works but jumps instantly without animation.
MCQ 15
How do you remove an inline style that was set with JavaScript?
  • A. element.style.color = null
  • B. element.style.color = ''
  • C. element.removeStyle('color')
  • D. delete element.style.color
Answer: B
B is correct. Setting a style property to an empty string removes that inline style, allowing stylesheet styles to take effect again.
MCQ 16
What prefix do CSS custom properties (variables) require?
  • A. $ (dollar sign)
  • B. @ (at sign)
  • C. -- (double hyphen)
  • D. # (hash)
Answer: C
C is correct. CSS custom properties must start with -- (double hyphen). Example: --primary-color: #a855f7;. They are referenced with var(--primary-color).
MCQ 17
What does getComputedStyle(element).display return for an element with display: flex in a stylesheet?
  • A. '' (empty string)
  • B. flex
  • C. block
  • D. undefined
Answer: B
B is correct. getComputedStyle returns the actual computed value from all CSS sources. If the stylesheet sets display: flex, it returns "flex".
MCQ 18
What is requestAnimationFrame used for?
  • A. Loading images faster
  • B. Scheduling code to run before the next browser repaint, ideal for smooth animations
  • C. Creating CSS keyframe animations
  • D. Pausing JavaScript execution
Answer: B
B is correct. requestAnimationFrame(callback) tells the browser to call your function before the next repaint (typically 60fps). This is the most efficient way to create smooth JavaScript-driven animations.
MCQ 19
Which is the preferred way to change element styles: inline styles or CSS classes?
  • A. Inline styles (element.style) are always preferred
  • B. CSS classes (classList) are preferred for predefined styles; inline styles for dynamic values
  • C. They are equivalent
  • D. Neither -- use only stylesheets
Answer: B
B is correct. CSS classes are preferred because they separate style from logic, are easier to manage, and work with CSS transitions. Use inline styles only for truly dynamic values that cannot be predefined (like positioning based on mouse coordinates).
MCQ 20
What happens if you set element.style.setProperty('--custom', 'blue') on a specific element instead of :root?
  • A. It does not work -- variables can only be set on :root
  • B. The variable overrides the :root value for that element and its descendants only
  • C. It changes the variable globally
  • D. An error is thrown
Answer: B
B is correct. CSS variables follow inheritance. Setting a variable on a specific element overrides the :root value for that element and all its children, while the rest of the page keeps the :root value.

Coding Challenges

Challenge 1: Dark Mode Toggle

Easy
Create a page with a heading, paragraph, and a toggle button. Define a .dark class on body that changes background to #1a1a2e and text to #f1f5f9. Clicking the button toggles dark mode. The button text should change between 'Dark Mode' and 'Light Mode'.
Sample Input
Click the toggle button
Sample Output
Page switches to dark background and light text. Button says 'Light Mode'.
Use classList.toggle on body. Use CSS transitions for smooth color changes. No inline styles for the theme.
<!DOCTYPE html>
<html>
<head><style>
  body { font-family: Arial; padding: 20px; transition: background 0.3s, color 0.3s; }
  body.dark { background: #1a1a2e; color: #f1f5f9; }
  button { padding: 10px 20px; cursor: pointer; }
</style></head>
<body>
  <h1>My Page</h1>
  <p>Toggle the theme with the button below.</p>
  <button id="btn">Dark Mode</button>
  <script>
    const btn = document.getElementById("btn");
    btn.addEventListener("click", function() {
      const isDark = document.body.classList.toggle("dark");
      btn.textContent = isDark ? "Light Mode" : "Dark Mode";
    });
  </script>
</body>
</html>

Challenge 2: Font Size Controller

Easy
Create a paragraph of text and three buttons: 'A-' (decrease), 'A' (reset), 'A+' (increase). Clicking them should change the paragraph font size by 2px. Show the current font size. Minimum 12px, maximum 36px.
Sample Input
Click A+ three times
Sample Output
Font grows from 16px to 22px. Display shows '22px'.
Use element.style.fontSize. Use getComputedStyle for the initial value. Clamp between 12 and 36.
<!DOCTYPE html>
<html>
<body>
  <p id="text" style="font-size: 16px;">This is sample text. Change the font size with the buttons below.</p>
  <button id="minus">A-</button>
  <button id="reset">A</button>
  <button id="plus">A+</button>
  <span id="display">16px</span>
  <script>
    const text = document.getElementById("text");
    const display = document.getElementById("display");
    let size = 16;
    function update() { text.style.fontSize = size + "px"; display.textContent = size + "px"; }
    document.getElementById("plus").addEventListener("click", function() { if (size < 36) { size += 2; update(); } });
    document.getElementById("minus").addEventListener("click", function() { if (size > 12) { size -= 2; update(); } });
    document.getElementById("reset").addEventListener("click", function() { size = 16; update(); });
  </script>
</body>
</html>

Challenge 3: CSS Variable Theme Switcher

Medium
Define 4 CSS variables on :root (--bg, --text, --primary, --accent). Create 4 theme presets (Purple, Ocean, Forest, Sunset) as JavaScript objects. Create 4 buttons. Clicking each button changes all 4 variables using setProperty. All elements on the page should use var() references so they update automatically.
Sample Input
Click 'Ocean' button
Sample Output
Entire page switches to blue/teal color scheme.
Use CSS custom properties. Use setProperty to change them. All colors must use var() in CSS.
<!DOCTYPE html>
<html>
<head><style>
  :root { --bg: #fff; --text: #1a1a2e; --primary: #a855f7; --accent: #06b6d4; }
  body { background: var(--bg); color: var(--text); font-family: Arial; padding: 20px; transition: all 0.3s; }
  h1 { color: var(--primary); }
  .card { background: var(--primary); color: white; padding: 20px; border-radius: 12px; margin: 16px 0; }
  button { padding: 8px 16px; margin: 4px; cursor: pointer; border: 2px solid var(--primary); border-radius: 6px; background: var(--accent); color: white; }
</style></head>
<body>
  <h1>Theme Demo</h1>
  <button id="t1">Purple</button><button id="t2">Ocean</button><button id="t3">Forest</button><button id="t4">Sunset</button>
  <div class="card"><h3>Card</h3><p>This card uses the primary color.</p></div>
  <script>
    const themes = {
      t1: {"--bg":"#fff","--text":"#1a1a2e","--primary":"#a855f7","--accent":"#06b6d4"},
      t2: {"--bg":"#f0f9ff","--text":"#0c4a6e","--primary":"#0369a1","--accent":"#06b6d4"},
      t3: {"--bg":"#f0fdf4","--text":"#14532d","--primary":"#15803d","--accent":"#a3e635"},
      t4: {"--bg":"#fff7ed","--text":"#7c2d12","--primary":"#ea580c","--accent":"#facc15"}
    };
    const root = document.documentElement;
    Object.keys(themes).forEach(function(id) {
      document.getElementById(id).addEventListener("click", function() {
        Object.entries(themes[id]).forEach(function(entry) { root.style.setProperty(entry[0], entry[1]); });
      });
    });
  </script>
</body>
</html>

Challenge 4: Scroll Progress Bar

Medium
Create a fixed progress bar at the top of the page that fills from left to right as the user scrolls. At the top, width is 0%. At the bottom, width is 100%. Use a gradient background for the bar. Also add a percentage display.
Sample Input
Scroll halfway down the page
Sample Output
Progress bar is 50% wide. Display shows '50%'.
Use window.scrollY, document.documentElement.scrollHeight, and window.innerHeight for calculation. Use element.style.width for the bar.
<!DOCTYPE html>
<html>
<head><style>
  body { font-family: Arial; padding: 20px; margin: 0; }
  .bar { position: fixed; top: 0; left: 0; height: 4px; background: linear-gradient(to right, #a855f7, #06b6d4); z-index: 100; transition: width 0.1s; }
  .pct { position: fixed; top: 8px; right: 16px; font-size: 13px; color: #666; z-index: 100; }
  .content { padding-top: 30px; }
  section { min-height: 50vh; padding: 40px 0; border-bottom: 1px solid #eee; }
</style></head>
<body>
  <div class="bar" id="bar"></div>
  <div class="pct" id="pct">0%</div>
  <div class="content">
    <section><h2>Section 1</h2><p>Scroll down to see the progress bar fill.</p></section>
    <section><h2>Section 2</h2><p>Content here.</p></section>
    <section><h2>Section 3</h2><p>More content.</p></section>
    <section><h2>Section 4</h2><p>Almost there.</p></section>
    <section><h2>Section 5</h2><p>Bottom of page.</p></section>
  </div>
  <script>
    const bar = document.getElementById("bar");
    const pct = document.getElementById("pct");
    window.addEventListener("scroll", function() {
      const scrollable = document.documentElement.scrollHeight - window.innerHeight;
      const percent = Math.round((window.scrollY / scrollable) * 100);
      bar.style.width = percent + "%";
      pct.textContent = percent + "%";
    });
  </script>
</body>
</html>

Challenge 5: Animated Card Flip

Hard
Create a card with a front and back face. Clicking the card flips it with a 3D rotation animation. The front shows a question. The back shows the answer. Use CSS transform: rotateY and backface-visibility. JavaScript just toggles a class.
Sample Input
Click the card
Sample Output
Card flips 180 degrees revealing the answer on the back. Click again to flip back.
Use CSS 3D transforms (perspective, rotateY, backface-visibility). JavaScript should only toggle a 'flipped' class.
<!DOCTYPE html>
<html>
<head><style>
  body { font-family: Arial; padding: 40px; display: flex; justify-content: center; }
  .card-container { perspective: 800px; width: 300px; height: 200px; cursor: pointer; }
  .card { width: 100%; height: 100%; position: relative; transition: transform 0.6s; transform-style: preserve-3d; }
  .card.flipped { transform: rotateY(180deg); }
  .front, .back { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; align-items: center; justify-content: center; border-radius: 12px; padding: 20px; box-sizing: border-box; text-align: center; font-size: 18px; }
  .front { background: #a855f7; color: white; }
  .back { background: #06b6d4; color: white; transform: rotateY(180deg); }
</style></head>
<body>
  <div class="card-container" id="container">
    <div class="card" id="card">
      <div class="front"><strong>What does DOM stand for?</strong></div>
      <div class="back"><strong>Document Object Model</strong></div>
    </div>
  </div>
  <script>
    document.getElementById("container").addEventListener("click", function() {
      document.getElementById("card").classList.toggle("flipped");
    });
  </script>
</body>
</html>

Challenge 6: Interactive Color Mixer

Hard
Create three range sliders for Red, Green, and Blue (0-255). As the user adjusts any slider, update: (1) a preview box showing the mixed color as background, (2) the hex code display, (3) the RGB display, (4) CSS variables --red, --green, --blue that control text labels. Show the numeric value next to each slider.
Sample Input
Set R:168, G:85, B:247
Sample Output
Preview shows purple (#a855f7). Displays: 'HEX: #a855f7' and 'RGB: rgb(168, 85, 247)'.
Use input event on range sliders. Use CSS custom properties for dynamic coloring. Calculate hex from RGB values.
<!DOCTYPE html>
<html>
<head><style>
  body { font-family: Arial; padding: 20px; }
  .slider-group { margin: 8px 0; display: flex; align-items: center; gap: 12px; }
  input[type=range] { width: 200px; }
  #preview { width: 200px; height: 200px; border-radius: 12px; margin: 16px 0; border: 1px solid #ddd; }
  .value { font-family: monospace; font-size: 18px; min-width: 40px; }
  .code { font-family: monospace; font-size: 16px; margin: 4px 0; }
</style></head>
<body>
  <h2>Color Mixer</h2>
  <div class="slider-group"><label style="color:red;width:50px;">Red</label><input type="range" id="r" min="0" max="255" value="168"><span class="value" id="rv">168</span></div>
  <div class="slider-group"><label style="color:green;width:50px;">Green</label><input type="range" id="g" min="0" max="255" value="85"><span class="value" id="gv">85</span></div>
  <div class="slider-group"><label style="color:blue;width:50px;">Blue</label><input type="range" id="b" min="0" max="255" value="247"><span class="value" id="bv">247</span></div>
  <div id="preview"></div>
  <div class="code" id="hex"></div>
  <div class="code" id="rgb"></div>
  <script>
    const rSlider = document.getElementById("r");
    const gSlider = document.getElementById("g");
    const bSlider = document.getElementById("b");
    function toHex(n) { return Number(n).toString(16).padStart(2, "0"); }
    function update() {
      const r = rSlider.value, g = gSlider.value, b = bSlider.value;
      document.getElementById("rv").textContent = r;
      document.getElementById("gv").textContent = g;
      document.getElementById("bv").textContent = b;
      const hex = "#" + toHex(r) + toHex(g) + toHex(b);
      document.getElementById("preview").style.backgroundColor = hex;
      document.getElementById("hex").textContent = "HEX: " + hex;
      document.getElementById("rgb").textContent = "RGB: rgb(" + r + ", " + g + ", " + b + ")";
    }
    rSlider.addEventListener("input", update);
    gSlider.addEventListener("input", update);
    bSlider.addEventListener("input", update);
    update();
  </script>
</body>
</html>

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn web development with a live mentor?

Explore our Frontend Masterclass