Junior Frontend Developer Interview Questions: HTML, CSS & JavaScript Fundamentals

Milad Bonakdar
Author
Master the core fundamentals with 32 essential interview questions covering HTML, CSS, and JavaScript. Perfect preparation for junior frontend developer interviews in 2024-2025.
Introduction
This comprehensive guide contains 32 carefully selected interview questions covering the core fundamentals of frontend development: HTML, CSS, and JavaScript. These are the questions that junior frontend developers actually encounter in 2024-2025 interviews. Each question includes a thorough answer, rarity assessment, and difficulty rating based on analysis of hundreds of real interviews from major tech companies and startups.
This is Part 1 of our complete interview guide. For questions on React, build tools, performance optimization, debugging, accessibility, testing, and soft skills, check out Part 2: React, Tools & Advanced Topics.
HTML Fundamentals (7 Questions)
1. What are semantic HTML elements and why are they important?
Answer: Semantic HTML elements clearly describe their meaning and purpose to both browsers and developers. Examples include <header>, <nav>, <main>, <article>, <section>, <aside>, and <footer>. They're important because they improve accessibility for screen readers and assistive technologies, enhance SEO by helping search engines understand content structure, and make code more maintainable and readable. Unlike generic <div> and <span> elements which provide no context, semantic elements communicate the role and meaning of content.
Rarity: Common
Difficulty: Easy
2. Explain the difference between inline, block, and inline-block elements
Answer:
- Block elements start on a new line and take up the full width available (e.g.,
<div>,<p>,<h1>). You can set width and height properties. - Inline elements stay on the same line and only take up as much width as needed (e.g.,
<span>,<a>,<strong>). You cannot set width or height. - Inline-block elements stay inline but allow you to set width and height like block elements. This combines the flow of inline with the sizing capabilities of block.
Rarity: Common
Difficulty: Easy
3. What are void (self-closing) elements in HTML?
Answer: Void elements are HTML elements that don't have closing tags and cannot contain content. Common examples include: <img>, <br>, <hr>, <input>, <meta>, <link>, <area>, <base>, <col>, <embed>, and <source>. These elements are complete with just their opening tag and attributes. For example, <img src="photo.jpg" alt="description"> doesn't need a closing </img> tag.
Rarity: Common
Difficulty: Easy
4. How do you make a website accessible? What HTML attributes improve accessibility?
Answer: To make websites accessible:
- Use semantic HTML elements (
<nav>,<main>,<header>,<footer>) - Provide
altattributes for all images describing their content - Maintain proper heading hierarchy (H1-H6) without skipping levels
- Label form inputs with
<label>elements using theforattribute - Ensure keyboard accessibility with proper tab order
- Use ARIA attributes when semantic HTML isn't sufficient:
aria-label,aria-describedby,aria-hidden,aria-live - Add
roleattributes for complex widgets - Ensure sufficient color contrast (4.5:1 for normal text)
- Make interactive elements focusable and provide visible focus indicators
Rarity: Common
Difficulty: Medium
5. Explain the difference between GET and POST methods in forms
Answer:
- GET: Appends form data to the URL as query parameters, making data visible in the browser. Has length limitations (~2000 characters), can be cached and bookmarked, insecure for sensitive data. Used for retrieving data where the request doesn't modify server state (searches, filters).
- POST: Sends data in the request body, not visible in URL. No length restrictions, cannot be cached by default, more secure for sensitive information. Used for submitting data that modifies server state (login forms, file uploads, creating records).
Example: Search forms typically use GET so results can be bookmarked, while login forms use POST to hide credentials.
Rarity: Common
Difficulty: Easy-Medium
6. What is the purpose of the <meta> tag?
Answer: The <meta> tag provides metadata about the HTML document that isn't displayed on the page but is used by browsers, search engines, and other web services. Common uses include:
- Character encoding:
<meta charset="UTF-8"> - Viewport settings for responsive design:
<meta name="viewport" content="width=device-width, initial-scale=1.0"> - SEO descriptions:
<meta name="description" content="Page description"> - Author information:
<meta name="author" content="Name"> - Keywords (less relevant now):
<meta name="keywords" content="keyword1, keyword2">
Rarity: Common
Difficulty: Easy
7. What's the difference between <script>, <script async>, and <script defer>?
Answer:
- Regular
<script>: Blocks HTML parsing while the script downloads and executes. Page rendering stops until the script completes. <script async>: Downloads the script in parallel with HTML parsing, but executes immediately when ready (potentially blocking parsing). Execution order is not guaranteed. Good for independent scripts like analytics.<script defer>: Downloads in parallel but executes only after HTML parsing completes, maintaining script order. Best for scripts that depend on the DOM or other scripts.
Best practice: Place <script defer> in the <head> for optimal performance while ensuring proper execution order.
Rarity: Uncommon
Difficulty: Medium
CSS Fundamentals (10 Questions)
8. Explain the CSS Box Model
Answer: The CSS Box Model describes how elements are rendered with four components (from inside out):
- Content: The actual content (text, images)
- Padding: Space between content and border (inside)
- Border: The border surrounding padding
- Margin: Space outside the border (between elements)
The box-sizing property affects calculations:
box-sizing: content-box(default): Width/height apply only to content; padding and border are addedbox-sizing: border-box: Width/height include content + padding + border (more intuitive)
Example: With box-sizing: border-box, an element with width: 100px; padding: 10px; border: 2px; stays exactly 100px wide.
Rarity: Common
Difficulty: Easy-Medium
9. Explain CSS specificity and how it works
Answer: CSS specificity determines which styles are applied when multiple rules target the same element. Specificity is calculated by counting selectors:
- Inline styles: 1000 points
- IDs: 100 points each
- Classes, attributes, pseudo-classes: 10 points each
- Elements, pseudo-elements: 1 point each
Examples:
#nav .button= 110 (1 ID + 1 class).header .nav a= 21 (2 classes + 1 element)div p= 2 (2 elements)
When specificity is equal, the last rule wins (cascading). !important overrides everything but should be avoided. Best practice: Use classes for styling, avoid IDs and !important.
Rarity: Common
Difficulty: Medium
10. What is Flexbox and when would you use it?
Answer: Flexbox is a one-dimensional layout system for arranging items along a single axis (row or column).
Parent (flex container) properties:
display: flex- enables flexboxflex-direction- row, column, row-reverse, column-reversejustify-content- alignment along main axis (center, space-between, space-around)align-items- alignment along cross axis (center, flex-start, flex-end, stretch)flex-wrap- controls wrapping (nowrap, wrap)
Child (flex item) properties:
flex-grow- how much item grows relative to othersflex-shrink- how much item shrinksflex-basis- initial size before growing/shrinkingalign-self- override align-items for individual item
Use Flexbox for: Navigation bars, card layouts, centering elements, distributing space evenly, aligning items within containers.
Rarity: Common
Difficulty: Medium
11. What is CSS Grid and how does it differ from Flexbox?
Answer: CSS Grid is a two-dimensional layout system for creating complex layouts with rows AND columns simultaneously.
Key differences:
- Grid: Two-dimensional (rows + columns), best for page layouts
- Flexbox: One-dimensional (single axis), best for components
Grid properties:
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* 3 columns */
grid-template-rows: 100px auto 50px;
grid-gap: 20px; /* or gap */
}When to use:
- Grid: Overall page layouts, magazine-style designs, complex grid structures
- Flexbox: Navigation bars, cards, components within grid cells
- Both together: Grid for macro layout, Flexbox for micro layouts
Rarity: Common
Difficulty: Medium
12. How do you center a div horizontally and vertically?
Answer:
Modern approaches (preferred):
/* Flexbox */
.parent {
display: flex;
justify-content: center;
align-items: center;
}
/* Grid */
.parent {
display: grid;
place-items: center;
}Legacy approaches:
/* Absolute positioning */
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* Margin auto (horizontal only, requires width) */
.child {
margin: 0 auto;
width: 300px;
}Flexbox and Grid are now the standard solutions as they're cleaner and more flexible.
Rarity: Common
Difficulty: Easy-Medium
13. Explain CSS positioning: static, relative, absolute, fixed, and sticky
Answer:
- Static (default): Normal document flow, no special positioning
- Relative: Positioned relative to its normal position using top/right/bottom/left. Original space in document flow is preserved. Often used as positioning context for absolute children.
- Absolute: Removed from flow, positioned relative to nearest positioned ancestor (or viewport if none). Doesn't affect other elements.
- Fixed: Removed from flow, positioned relative to viewport. Stays in place when scrolling.
- Sticky: Hybrid of relative and fixed. Acts relative until scroll threshold, then becomes fixed. Useful for sticky headers that start in-flow.
Example: Navigation that becomes fixed after scrolling uses position: sticky; top: 0;
Rarity: Common
Difficulty: Medium
14. What's the difference between display: none, visibility: hidden, and opacity: 0?
Answer:
display: none: Element completely removed from document flow, takes no space, not accessible to screen readers, no pointer eventsvisibility: hidden: Element invisible but maintains space in layout, still in DOM, not accessible to screen readers, no pointer eventsopacity: 0: Element invisible but maintains space, still in DOM, STILL accessible to screen readers, STILL receives pointer events
Use cases:
display: none- toggling visibility (modals, dropdowns)visibility: hidden- maintaining layout while hidingopacity: 0- fade animations, keeping element interactive
Rarity: Common
Difficulty: Easy-Medium
15. What are CSS pseudo-classes and pseudo-elements? Provide examples.
Answer:
Pseudo-classes (single colon) - Select elements based on state or position:
a:hover { color: blue; } /* mouse over */
input:focus { border: 2px solid blue; } /* keyboard focus */
li:nth-child(odd) { background: #eee; } /* odd list items */
button:disabled { opacity: 0.5; } /* disabled state */Other examples: :active, :checked, :first-child, :last-child, :nth-of-type()
Pseudo-elements (double colon) - Style specific parts or insert content:
p::first-line { font-weight: bold; } /* first line of paragraph */
p::first-letter { font-size: 2em; } /* drop cap */
.icon::before { content: "→"; } /* insert content */
input::placeholder { color: gray; } /* placeholder text */Pseudo-elements are great for decorative elements without adding HTML.
Rarity: Common
Difficulty: Medium
16. How do you create responsive layouts? Explain media queries.
Answer: Responsive layouts adapt to different screen sizes using:
Media Queries:
/* Mobile first approach (recommended) */
.container { width: 100%; }
@media screen and (min-width: 768px) {
.container { width: 750px; } /* Tablet */
}
@media screen and (min-width: 1024px) {
.container { width: 960px; } /* Desktop */
}Common breakpoints:
- 320px: Small mobile
- 768px: Tablet
- 1024px: Desktop
- 1440px: Large desktop
Other responsive techniques:
- Fluid layouts (percentages,
vw/vhunits) - Flexible Flexbox and Grid
- Responsive images (
max-width: 100%,srcsetattribute) min-widthqueries (mobile-first) vsmax-width(desktop-first)
Rarity: Common
Difficulty: Medium
17. What is z-index and how does it work?
Answer: z-index controls the stacking order of positioned elements (relative, absolute, fixed, sticky) along the z-axis (front to back).
Key points:
- Only works on positioned elements (not static)
- Higher values appear in front
- Can use negative values
- Default value is
auto(effectively 0) - Creates a "stacking context" which affects how children stack
Common gotcha:
.parent { position: relative; z-index: 1; }
.child { position: absolute; z-index: 9999; }The child with z-index 9999 can't appear above another element with z-index 2 that's outside the parent's stacking context.
Rarity: Common
Difficulty: Medium
JavaScript Fundamentals (15 Questions)
18. Explain the difference between var, let, and const
Answer:
var: Function-scoped, hoisted and initialized withundefined, can be re-declared, largely deprecated in modern codelet: Block-scoped, hoisted but in Temporal Dead Zone (TDZ) until declaration, cannot be re-declared in same scopeconst: Block-scoped, hoisted but in TDZ, must be initialized at declaration, cannot be reassigned (but object/array contents can be mutated)
Best practices:
- Use
constby default - Use
letwhen you need to reassign - Never use
varin modern JavaScript
Example:
const name = "Alice"; // Can't reassign
let count = 0; // Can reassign
count = 1; // OK
name = "Bob"; // Error!
const user = { age: 25 };
user.age = 26; // OK - mutating object property
user = {}; // Error - reassigningRarity: Common
Difficulty: Easy
19. What are closures and provide a practical example?
Answer: A closure is when an inner function has access to variables from its outer (enclosing) function's scope, even after the outer function has returned. The inner function "closes over" these variables.
Example:
function createCounter() {
let count = 0; // Private variable
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3The inner function maintains access to count even though createCounter has finished executing. This enables data privacy - count can't be accessed directly from outside.
Use cases: Data privacy, function factories, callbacks, module patterns, event handlers
Rarity: Common
Difficulty: Medium
20. Explain == vs === in JavaScript
Answer:
==(loose equality): Performs type coercion before comparison, converts types to match===(strict equality): Checks both value AND type, no type coercion
Examples:
5 == '5' // true (string coerced to number)
5 === '5' // false (different types)
null == undefined // true (special case)
null === undefined // false (different types)
0 == false // true (both coerced)
0 === false // false (number vs boolean)Best practice: Always use === and !== to avoid unexpected bugs from type coercion.
Rarity: Common
Difficulty: Easy
21. What is hoisting in JavaScript?
Answer: Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope during the compilation phase, before code execution.
Different hoisting behaviors:
console.log(x); // undefined (hoisted, initialized)
var x = 5;
console.log(y); // ReferenceError (hoisted but in TDZ)
let y = 5;
sayHello(); // "Hello!" (function fully hoisted)
function sayHello() {
console.log("Hello!");
}
sayHi(); // TypeError (not a function)
var sayHi = function() {
console.log("Hi!");
};Key points:
vardeclarations are hoisted and initialized withundefinedlet/constare hoisted but remain uninitialized (Temporal Dead Zone)- Function declarations are fully hoisted (including implementation)
- Function expressions are not fully hoisted
Rarity: Common
Difficulty: Medium
22. Explain the this keyword and how it differs in arrow functions
Answer: this refers to the context in which a function is executed. Its value depends on HOW the function is called.
Regular functions:
const obj = {
name: "John",
greet: function() {
console.log(this.name); // "John"
}
};
obj.greet(); // this = obj
const greet = obj.greet;
greet(); // this = undefined (strict mode) or windowArrow functions:
const obj = {
name: "John",
greet: () => {
console.log(this.name); // undefined
}
};
obj.greet(); // this = lexical scope (enclosing context)Key differences:
- Regular functions:
thisdetermined by call site - Arrow functions:
thislexically inherited from enclosing scope - Arrow functions don't have their own
this,arguments, orsuper
Use case: Arrow functions are great for callbacks where you want to preserve outer this:
class Timer {
start() {
setTimeout(() => {
console.log(this); // Timer instance (lexical)
}, 1000);
}
}Rarity: Common
Difficulty: Medium-Hard
23. What are template literals and their benefits?
Answer: Template literals are string literals using backticks (`) that support string interpolation and multi-line strings.
Features:
const name = "Alice";
const age = 25;
// String interpolation
const message = `Hello, my name is ${name} and I'm ${age} years old.`;
// Multi-line strings
const html = `
<div>
<h1>${title}</h1>
<p>${content}</p>
</div>
`;
// Expression evaluation
const price = `Total: $${(quantity * unitPrice).toFixed(2)}`;Benefits:
- Cleaner syntax than string concatenation
- No need for
\nfor line breaks - Can embed any JavaScript expression with
${} - Better for HTML/CSS generation
Rarity: Common
Difficulty: Easy
24. Explain Promises and their three states
Answer: A Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
Three states:
- Pending: Initial state, operation not complete
- Fulfilled: Operation completed successfully
- Rejected: Operation failed
Example:
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve({ data: "User info" });
} else {
reject(new Error("Failed to fetch"));
}
}, 1000);
});
fetchData
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log("Done"));Benefits over callbacks:
- Avoids callback hell
- Chainable with
.then() - Better error handling with
.catch() - Can use Promise.all() for parallel operations
Rarity: Common
Difficulty: Medium
25. What is async/await and how does it improve code readability?
Answer: async/await is syntactic sugar built on Promises that makes asynchronous code look and behave more like synchronous code.
Example:
// With Promises (harder to read)
function fetchUserData() {
return fetch('/api/user')
.then(response => response.json())
.then(data => {
return fetch(`/api/posts/${data.id}`);
})
.then(response => response.json())
.catch(error => console.error(error));
}
// With async/await (cleaner)
async function fetchUserData() {
try {
const response = await fetch('/api/user');
const user = await response.json();
const postsResponse = await fetch(`/api/posts/${user.id}`);
const posts = await postsResponse.json();
return posts;
} catch (error) {
console.error(error);
}
}Key points:
asyncfunction always returns a Promiseawaitpauses execution until Promise resolves- Use
try/catchfor error handling - Makes sequential operations clearer
- Error handling more natural than
.catch()
Rarity: Common
Difficulty: Medium
26. Explain the Event Loop and how JavaScript handles asynchronous operations
Answer: JavaScript is single-threaded but handles async operations through the Event Loop mechanism.
Components:
- Call Stack: Executes synchronous code (LIFO)
- Web APIs: Handle async operations (setTimeout, fetch, DOM events)
- Callback Queue (Task Queue): Holds callbacks from Web APIs
- Microtask Queue: Holds Promise callbacks (higher priority)
- Event Loop: Moves tasks from queues to call stack when stack is empty
Execution order:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
// Explanation:
// - Sync code (1, 4) runs first
// - Microtasks (Promise) run before macrotasks
// - Macrotasks (setTimeout) run lastOrder of execution: Call Stack → Microtask Queue → Callback Queue (Macrotasks)
Rarity: Common
Difficulty: Hard
27. How do you select and manipulate DOM elements?
Answer:
Selection methods:
// Modern (preferred)
const element = document.querySelector('#myId');
const elements = document.querySelectorAll('.myClass');
const firstItem = document.querySelector('.list-item');
// Legacy (still valid)
const elem = document.getElementById('myId');
const elems = document.getElementsByClassName('myClass');
const tags = document.getElementsByTagName('div');Manipulation:
// Content
element.textContent = 'New text';
element.innerHTML = '<span>HTML content</span>';
// Styling
element.style.color = 'blue';
element.style.backgroundColor = '#eee';
// Classes
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('visible');
element.classList.contains('active');
// Attributes
element.setAttribute('data-id', '123');
element.getAttribute('data-id');
// Creating elements
const newDiv = document.createElement('div');
newDiv.textContent = 'Hello';
document.body.appendChild(newDiv);Rarity: Common
Difficulty: Easy
28. Explain event delegation and why it's useful
Answer: Event delegation is attaching a single event listener to a parent element instead of multiple listeners to child elements, leveraging event bubbling.
Without delegation (inefficient):
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('click', handleClick);
});With delegation (efficient):
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.matches('.item')) {
handleClick(e);
}
});Benefits:
- Better performance: Single listener vs many
- Works with dynamic elements: Automatically handles items added later
- Lower memory usage: Fewer event listeners
- Cleaner code: Centralized event handling
Use case: Lists where items can be added/removed dynamically (todo lists, shopping carts, comment sections)
Rarity: Common
Difficulty: Medium
29. What is event bubbling? How do you stop propagation?
Answer: Event bubbling is when an event triggered on a child element "bubbles up" through its ancestors to the document root.
Three phases:
- Capturing Phase: Event travels down from window to target
- Target Phase: Event reaches target element
- Bubbling Phase: Event bubbles up from target to window (default)
Example:
<div id="parent">
<button id="child">Click me</button>
</div>
<script>
document.getElementById('parent').addEventListener('click', () => {
console.log('Parent clicked');
});
document.getElementById('child').addEventListener('click', (e) => {
console.log('Child clicked');
// Event bubbles to parent
});
// Clicking button logs: "Child clicked", then "Parent clicked"
</script>Stopping propagation:
element.addEventListener('click', (e) => {
e.stopPropagation(); // Stops bubbling
e.preventDefault(); // Prevents default behavior (form submit, link navigation)
});Rarity: Common
Difficulty: Medium
30. Explain destructuring for objects and arrays
Answer: Destructuring extracts values from arrays or properties from objects into distinct variables.
Array destructuring:
const colors = ['red', 'green', 'blue', 'yellow'];
const [first, second, ...rest] = colors;
// first = 'red'
// second = 'green'
// rest = ['blue', 'yellow']
// Skip elements
const [primary, , tertiary] = colors;
// primary = 'red', tertiary = 'blue'Object destructuring:
const user = {
name: 'Alice',
age: 25,
email: 'alice@example.com'
};
const { name, age, city = 'NYC' } = user;
// name = 'Alice'
// age = 25
// city = 'NYC' (default value)
// Rename variables
const { name: userName, age: userAge } = user;
// Nested destructuring
const { address: { street, zip } } = person;Function parameters:
function greet({ name, age = 18 }) {
console.log(`Hello ${name}, age ${age}`);
}
greet({ name: 'Bob', age: 25 });Rarity: Common
Difficulty: Easy-Medium
31. Explain the spread operator and rest parameters
Answer:
Spread operator (...) - Expands iterables:
// Arrays
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const combined = [...arr1, ...arr2];
// Objects (shallow copy)
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 }; // Immutable update
// Function arguments
const numbers = [1, 2, 3];
Math.max(...numbers); // 3Rest parameters (...) - Collects multiple elements:
// Function parameters
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
// Array destructuring
const [first, ...remaining] = [1, 2, 3, 4];
// first = 1, remaining = [2, 3, 4]
// Object destructuring
const { name, ...otherProps } = user;Key difference: Spread expands, rest collects
Rarity: Common
Difficulty: Easy-Medium
32. What are common array methods and when would you use each?
Answer:
Transformation methods:
// map - Transform each element, returns new array
const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]
// filter - Keep elements matching condition
const evens = [1, 2, 3, 4].filter(x => x % 2 === 0); // [2, 4]
// reduce - Reduce to single value
const sum = [1, 2, 3].reduce((acc, val) => acc + val, 0); // 6Search methods:
// find - First element matching condition
const found = users.find(user => user.id === 5);
// findIndex - Index of first match
const index = arr.findIndex(x => x > 10);
// includes - Check if value exists
const hasValue = arr.includes(5); // true/falseTesting methods:
// some - At least one element matches
const hasEven = [1, 3, 5, 6].some(x => x % 2 === 0); // true
// every - All elements match
const allPositive = [1, 2, 3].every(x => x > 0); // trueSide effects (no return value useful):
// forEach - Iterate without returning new array
arr.forEach(item => console.log(item));Rarity: Common
Difficulty: Easy-Medium





