HTML Interview Questions

20+ HTML interview questions and answers in quiz-style format, answered by ex-FAANG interviewers
Solved by ex-interviewers
Covers critical topics

HTML interview questions are designed to assess your understanding of web development fundamentals and best practices. Interviewers typically focus on key topics such as:

  • Accessibility: Ensuring websites are accessible to users with disabilities using semantic HTML and ARIA roles.
  • Semantics: Recognizing the importance of semantic HTML tags for SEO, accessibility, and code clarity.
  • Forms: Building forms with proper input validation, accessibility features, and efficient handling of form submissions.
  • Multimedia: Embedding and managing images, audio, and video in HTML while optimizing for performance and accessibility.
  • Best Practices: Structuring HTML for readability, maintainability, and performance, including the proper use of meta tags, link attributes, and media queries.
  • SEO Optimization: Using semantic HTML elements and metadata to boost search engine ranking and improve web performance.

Below, you’ll find 20+ carefully curated HTML interview questions covering everything from core concepts to best practices and optimization strategies.

Each question includes:

  • Quick Answers (TL;DR): Concise, clear responses to help you answer confidently.
  • Detailed Explanations: In-depth insights to ensure you not only know the answers but understand the reasoning behind them.

Unlike most lists, our questions are carefully curated by real senior and staff engineers from top tech companies like Amazon, Meta, and more—not anonymous contributors or AI-generated content. Start practicing below and get ready to ace your HTML interview!

If you're looking for HTML coding questions -We've got you covered as well, with:
Javascript coding
  • 70+ HTML coding interview questions
  • An in-browser coding workspace that mimics real interview conditions
  • Reference solutions from ex-interviewers at Big Tech companies
  • One-click automated, transparent test cases
  • Instant UI preview for UI-related questions
Get Started
Join 50,000+ engineers

What is the difference between `mouseenter` and `mouseover` event in JavaScript and browsers?

Topics
Web APIsHTMLJavaScript

TL;DR

The main difference lies in the bubbling behavior of mouseenter and mouseover events. mouseenter does not bubble while mouseover bubbles.

mouseenter events do not bubble. The mouseenter event is triggered only when the mouse pointer enters the element itself, not its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the mouseenter event will not be triggered on the parent element again, it's only triggered once upon entry of parent element without regard for its contents. If both parent and child have mouseenter listeners attached and the mouse pointer moves from the parent element to the child element, mouseenter will only fire for the child.

mouseover events bubble up the DOM tree. The mouseover event is triggered when the mouse pointer enters the element or one of its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the mouseover event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, mouseover will fire for both the parent and the child.

Propertymouseentermouseover
BubblingNoYes
TriggerOnly when entering itselfWhen entering itself and when entering descendants

mouseenter event:

  • Does not bubble: The mouseenter event does not bubble. It is only triggered when the mouse pointer enters the element to which the event listener is attached, not when it enters any child elements.
  • Triggered once: The mouseenter event is triggered only once when the mouse pointer enters the element, making it more predictable and easier to manage in certain scenarios.

A use case for mouseenter is when you want to detect the mouse entering an element without worrying about child elements triggering the event multiple times.

mouseover Event:

  • Bubbles up the DOM: The mouseover event bubbles up through the DOM. This means that if you have an event listener on a parent element, it will also trigger when the mouse pointer moves over any child elements.
  • Triggered multiple times: The mouseover event is triggered every time the mouse pointer moves over an element or any of its child elements. This can lead to multiple triggers if you have nested elements.

A use case for mouseover is when you want to detect when the mouse enters an element or any of its children and are okay with the events triggering multiple times.

Example

Here's an example demonstrating the difference between mouseover and mouseenter events:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mouse Events Example</title>
<style>
.parent {
width: 200px;
height: 200px;
background-color: lightblue;
padding: 20px;
}
.child {
width: 100px;
height: 100px;
background-color: lightcoral;
}
</style>
</head>
<body>
<div class="parent">
Parent Element
<div class="child">Child Element</div>
</div>
<script>
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');
// Mouseover event on parent.
parent.addEventListener('mouseover', () => {
console.log('Mouseover on parent');
});
// Mouseenter event on parent.
parent.addEventListener('mouseenter', () => {
console.log('Mouseenter on parent');
});
// Mouseover event on child.
child.addEventListener('mouseover', () => {
console.log('Mouseover on child');
});
// Mouseenter event on child.
child.addEventListener('mouseenter', () => {
console.log('Mouseenter on child');
});
</script>
</body>
</html>

Expected behavior

  • When the mouse enters the parent element:
    • The mouseover event on the parent will trigger.
    • The mouseenter event on the parent will trigger.
  • When the mouse enters the child element:
    • The mouseover event on the parent will trigger again because mouseover bubbles up from the child.
    • The mouseover event on the child will trigger.
    • The mouseenter event on the child will trigger.
    • The mouseenter event on the parent will not trigger again because mouseenter does not bubble.

Further reading

Explain the difference between `document.querySelector()` and `document.getElementById()`

Topics
Web APIsJavaScriptHTML

TL;DR

document.querySelector() and document.getElementById() are both methods used to select elements from the DOM, but they have key differences. document.querySelector() can select any element using a CSS selector and returns the first match, while document.getElementById() selects an element by its ID and returns the element with that specific ID.

// Using document.querySelector()
const element = document.querySelector('.my-class');
// Using document.getElementById()
const elementById = document.getElementById('my-id');

Difference between document.querySelector() and document.getElementById()

document.querySelector()

  • Can select elements using any valid CSS selector, including class, ID, tag, attribute, and pseudo-classes
  • Returns the first element that matches the specified selector
  • More versatile but slightly slower due to the flexibility of CSS selectors
// Select the first element with the class 'my-class'
const element = document.querySelector('.my-class');
// Select the first <div> element
const divElement = document.querySelector('div');
// Select the first element with the attribute data-role='button'
const buttonElement = document.querySelector('[data-role="button"]');

document.getElementById()

  • Selects an element by its ID attribute
  • Returns the element with the specified ID
  • Faster and more efficient for selecting elements by ID, but less versatile
// Select the element with the ID 'my-id'
const elementById = document.getElementById('my-id');

Key differences

  • Selector type: document.querySelector() uses CSS selectors, while document.getElementById() uses only the ID attribute.
  • Return value: document.querySelector() returns the first matching element, whereas document.getElementById() returns the element with the specified ID.
  • Performance: document.getElementById() is generally faster because it directly accesses the element by ID, while document.querySelector() has to parse the CSS selector.

Further reading

How do `<iframe>` on a page communicate?

Topics
Web APIsJavaScriptHTML

TL;DR

<iframe> elements on a page can communicate using the postMessage API. This allows for secure cross-origin communication between the parent page and the iframe. The postMessage method sends a message, and the message event listener receives it. Here's a simple example:

// In the parent page
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello from parent', '*');
// In the iframe
window.addEventListener('message', (event) => {
console.log(event.data); // 'Hello from parent'
});

How do <iframe> on a page communicate?

Using the postMessage API

The postMessage API is the most common and secure way for iframes to communicate with each other or with their parent page. This method allows for cross-origin communication, which is essential for modern web applications.

Sending a message

To send a message from the parent page to the iframe, you can use the postMessage method. Here’s an example:

// In the parent page
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello from parent', '*');

In this example, the parent page selects the iframe and sends a message to it. The second parameter, '*', is the target origin. It specifies the origin of the target window. Using '*' means the message can be received by any origin, but for security reasons, it's better to specify the exact origin.

Receiving a message

To receive a message in the iframe, you need to add an event listener for the message event:

// In the iframe
window.addEventListener('message', (event) => {
console.log(event.data); // 'Hello from parent'
});

The event object contains the data property, which holds the message sent by the parent page.

Security considerations

When using postMessage, it's crucial to consider security:

  • Specify the target origin: Instead of using '*', specify the exact origin to ensure that only messages from trusted sources are received.
  • Validate the message: Always validate the message content to prevent malicious data from being processed.

Example with target origin

Here’s an example with a specified target origin:

// In the parent page
const iframe = document.querySelector('iframe');
const targetOrigin = 'https://example.com';
iframe.contentWindow.postMessage('Hello from parent', targetOrigin);
// In the iframe
window.addEventListener('message', (event) => {
if (event.origin === 'https://parent.com') {
console.log(event.data); // 'Hello from parent'
}
});

In this example, the parent page sends a message only to https://example.com, and the iframe processes the message only if it comes from https://parent.com.

Further reading

How do you add, remove, and modify HTML elements using JavaScript?

Topics
Web APIsJavaScriptHTML

TL;DR

To add, remove, and modify HTML elements using JavaScript, you can use methods like createElement, appendChild, removeChild, and properties like innerHTML and textContent. For example, to add an element, you can create it using document.createElement and then append it to a parent element using appendChild. To remove an element, you can use removeChild on its parent. To modify an element, you can change its innerHTML or textContent.

// Adding an element
const newElement = document.createElement('div');
newElement.textContent = 'Hello, World!';
document.body.appendChild(newElement);
// Removing an element
const elementToRemove = document.getElementById('elementId');
elementToRemove.parentNode.removeChild(elementToRemove);
// Modifying an element
const elementToModify = document.getElementById('elementId');
elementToModify.innerHTML = 'New Content';

Adding, removing, and modifying HTML elements using JavaScript

Adding elements

To add an HTML element, you can use the document.createElement method to create a new element and then append it to a parent element using appendChild.

// Create a new div element
const newDiv = document.createElement('div');
// Set its content
newDiv.textContent = 'Hello, World!';
// Append the new element to the body
document.body.appendChild(newDiv);
// See the changed document by running the code
console.log(document.body);

You can also use insertBefore to insert the new element before an existing child element.

const parentElement = document.getElementById('parent');
const newElement = document.createElement('p');
newElement.textContent = 'Inserted Paragraph';
const referenceElement = document.getElementById('reference');
parentElement.insertBefore(newElement, referenceElement);

Removing elements

To remove an HTML element, you can use the removeChild method on its parent element.

// Select the element to be removed
const elementToRemove = document.getElementById('elementId');
// Remove the element
elementToRemove.parentNode.removeChild(elementToRemove);

Alternatively, you can use the remove method directly on the element.

const elementToRemove = document.getElementById('elementId');
elementToRemove.remove();

Modifying elements

To modify an HTML element, you can change its properties such as innerHTML, textContent, or attributes.

const elementToModify = document.createElement('div');
// Change its inner HTML
elementToModify.innerHTML = 'New Content';
// Change its text content
elementToModify.textContent = 'New Text Content';
// Change an attribute
elementToModify.setAttribute('class', 'new-class');
console.log(elementToModify);

You can also use methods like classList.add, classList.remove, and classList.toggle to modify the element's classes.

const element = document.getElementById('elementId');
// Add a class
element.classList.add('new-class');
// Remove a class
element.classList.remove('old-class');
// Toggle a class
element.classList.toggle('active');

Further reading

What is the difference between `event.preventDefault()` and `event.stopPropagation()`?

Topics
Web APIsHTMLJavaScript

TL;DR

event.preventDefault() is used to prevent the default action that belongs to the event, such as preventing a form from submitting. event.stopPropagation() is used to stop the event from bubbling up to parent elements, preventing any parent event handlers from being executed.


What is the difference between event.preventDefault() and event.stopPropagation()?

event.preventDefault()

event.preventDefault() is a method that cancels the event if it is cancelable, meaning that the default action that belongs to the event will not occur. For example, this can be used to prevent a form from being submitted:

document.querySelector('form').addEventListener('submit', function (event) {
event.preventDefault();
// Form submission is prevented
});

event.stopPropagation()

event.stopPropagation() is a method that prevents the event from bubbling up the DOM tree, stopping any parent handlers from being notified of the event. This is useful when you want to handle an event at a specific level and do not want it to trigger handlers on parent elements:

document.querySelector('.child').addEventListener('click', function (event) {
event.stopPropagation();
// Click event will not propagate to parent elements
});

Key differences

  • event.preventDefault() stops the default action associated with the event.
  • event.stopPropagation() stops the event from propagating (bubbling) up to parent elements.

Use cases

  • Use event.preventDefault() when you want to prevent the default behavior of an element, such as preventing a link from navigating or a form from submitting.
  • Use event.stopPropagation() when you want to prevent an event from reaching parent elements, which can be useful in complex UIs where multiple elements have event listeners.

Further reading

What is the difference between `innerHTML` and `textContent`?

Topics
Web APIsHTMLJavaScript

TL;DR

innerHTML and textContent are both properties used to get or set the content of an HTML element, but they serve different purposes. innerHTML returns or sets the HTML markup contained within the element, which means it can parse and render HTML tags. On the other hand, textContent returns or sets the text content of the element, ignoring any HTML tags and rendering them as plain text.

// Example of innerHTML
element.innerHTML = '<strong>Bold Text</strong>'; // Renders as bold text
// Example of textContent
element.textContent = '<strong>Bold Text</strong>'; // Renders as plain text: <strong>Bold Text</strong>

Difference between innerHTML and textContent

innerHTML

innerHTML is a property that allows you to get or set the HTML markup contained within an element. It can parse and render HTML tags, making it useful for dynamically updating the structure of a webpage.

Example
const element = document.getElementById('example');
element.innerHTML = '<strong>Bold Text</strong>'; // This will render as bold text
Use cases
  • Dynamically adding or updating HTML content
  • Rendering HTML tags and elements
Security considerations

Using innerHTML can expose your application to Cross-Site Scripting (XSS) attacks if you insert untrusted content. Always sanitize any user input before setting it as innerHTML.

textContent

textContent is a property that allows you to get or set the text content of an element. It ignores any HTML tags and renders them as plain text, making it safer for inserting user-generated content.

Example
const element = document.getElementById('example');
element.textContent = '<strong>Bold Text</strong>'; // This will render as plain text: <strong>Bold Text</strong>
Use cases
  • Safely inserting user-generated content
  • Stripping HTML tags from a string
Performance considerations

textContent is generally faster than innerHTML because it does not parse and render HTML tags. It simply updates the text content of the element.

Further reading

What is the DOM and how is it structured?

Topics
JavaScriptHTML

TL;DR

The DOM, or Document Object Model, is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. The DOM is structured as a tree of objects, where each node represents part of the document, such as elements, attributes, and text.


What is the DOM and how is it structured?

Definition

The Document Object Model (DOM) is a cross-platform and language-independent interface that treats an HTML, XHTML, or XML document as a tree structure. Each node in this tree represents a part of the document.

Structure

The DOM is structured as a hierarchical tree of nodes. Here are the main types of nodes:

  1. Document node: The root of the document tree. It represents the entire document.
  2. Element nodes: These represent HTML elements and form the bulk of the document tree.
  3. Attribute nodes: These are associated with element nodes and represent the attributes of those elements.
  4. Text nodes: These represent the text content within elements.
  5. Comment nodes: These represent comments in the HTML.

Example

Consider the following HTML:

<!doctype html>
<html>
<head>
<title>Document</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is a paragraph.</p>
</body>
</html>

The DOM tree for this document would look like this:

Document
└── html
├── head
│ └── title
│ └── "Document"
└── body
├── h1
│ └── "Hello, World!"
└── p
└── "This is a paragraph."

Accessing and manipulating the DOM

JavaScript can be used to access and manipulate the DOM. Here are some common methods:

  • document.getElementById(id): Selects an element by its ID.
  • document.querySelector(selector): Selects the first element that matches a CSS selector.
  • element.appendChild(node): Adds a new child node to an element.
  • element.removeChild(node): Removes a child node from an element.

Example:

// Create an <h1> element and add it to the DOM
const newElement = document.createElement('h1');
document.body.appendChild(newElement);
// Get the h1 element using querySelector
const heading = document.querySelector('h1');
heading.textContent = 'Hello, DOM!';
console.log(heading); // <h1>Hello, DOM!</h1>

Further reading

What's the difference between an "attribute" and a "property" in the DOM?

Topics
Web APIsJavaScriptHTML

TL;DR

Attributes are defined in the HTML and provide initial values for properties. Properties are part of the DOM and represent the current state of an element. For example, the value attribute of an <input> element sets its initial value, while the value property reflects the current value as the user interacts with it.


Difference between an "attribute" and a "property" in the DOM

Attributes

Attributes are defined in the HTML markup and provide initial values for elements. They are static and do not change once the page is loaded unless explicitly modified using JavaScript.

Example
<input type="text" value="initial value" />

In this example, value="initial value" is an attribute.

Properties

Properties are part of the DOM and represent the current state of an element. They are dynamic and can change as the user interacts with the page or through JavaScript.

Example
const inputElement = document.querySelector('input');
console.log(inputElement.value); // Logs the current value of the input element
inputElement.value = 'new value'; // Changes the current value of the input element

In this example, value is a property of the inputElement object.

Key differences

  • Initialization: Attributes initialize DOM properties.
  • State: Attributes are static, while properties are dynamic.
  • Access: Attributes can be accessed using getAttribute and setAttribute methods, while properties can be accessed directly on the DOM object.
Example
<input id="myInput" type="text" value="initial value" />
const inputElement = document.getElementById('myInput');
// Accessing attribute
console.log(inputElement.getAttribute('value')); // "initial value"
// Accessing property
console.log(inputElement.value); // "initial value"
// Changing property
inputElement.value = 'new value';
console.log(inputElement.value); // "new value"
console.log(inputElement.getAttribute('value')); // "initial value"

In this example, changing the value property does not affect the value attribute.

Further reading

Describe the difference between `<script>`, `<script async>` and `<script defer>`

Topics
HTMLJavaScript

TL;DR

All of these ways (<script>, <script async>, and <script defer>) are used to load and execute JavaScript files in an HTML document, but they differ in how the browser handles loading and execution of the script:

  • <script> is the default way of including JavaScript. The browser blocks HTML parsing while the script is being downloaded and executed. The browser will not continue rendering the page until the script has finished executing.
  • <script async> downloads the script asynchronously, in parallel with parsing the HTML. Executes the script as soon as it is available, potentially interrupting the HTML parsing. <script async> do not wait for each other and execute in no particular order.
  • <script defer> downloads the script asynchronously, in parallel with parsing the HTML. However, the execution of the script is deferred until HTML parsing is complete, in the order they appear in the HTML.

Here's a table summarizing the 3 ways of loading <script>s in a HTML document.

Feature<script><script async><script defer>
Parsing behaviorBlocks HTML parsingRuns parallel to parsingRuns parallel to parsing
Execution orderIn order of appearanceNot guaranteedIn order of appearance
DOM dependencyNoNoYes (waits for DOM)

What <script> tags are for

<script> tags are used to include JavaScript on a web page. The async and defer attributes are used to change how/when the loading and execution of the script happens.

<script>

For normal <script> tags without any async or defer, when they are encountered, HTML parsing is blocked, the script is fetched and executed immediately. HTML parsing resumes after the script is executed. This can block rendering of the page if the script is large.

Use <script> for critical scripts that the page relies on to render properly.

<!doctype html>
<html>
<head>
<title>Regular Script</title>
</head>
<body>
<!-- Content before the script -->
<h1>Regular Script Example</h1>
<p>This content will be rendered before the script executes.</p>
<!-- Regular script -->
<script src="regular.js"></script>
<!-- Content after the script -->
<p>This content will be rendered after the script executes.</p>
</body>
</html>

<script async>

In <script async>, the browser downloads the script file asynchronously (in parallel with HTML parsing) and executes it as soon as it is available (potentially before HTML parsing completes). The execution will not necessarily be executed in the order in which it appears in the HTML document. This can improve perceived performance because the browser doesn't wait for the script to download before continuing to render the page.

Use <script async> when the script is independent of any other scripts on the page, for example, analytics and ads scripts.

<!doctype html>
<html>
<head>
<title>Async Script</title>
</head>
<body>
<!-- Content before the script -->
<h1>Async Script Example</h1>
<p>This content will be rendered before the async script executes.</p>
<!-- Async script -->
<script async src="async.js"></script>
<!-- Content after the script -->
<p>
This content may be rendered before or after the async script executes.
</p>
</body>
</html>

<script defer>

Similar to <script async>, <script defer> also downloads the script in parallel to HTML parsing but the script is only executed when the document has been fully parsed and before firing DOMContentLoaded. If there are multiple of them, each deferred script is executed in the order they appeared in the HTML document.

If a script relies on a fully-parsed DOM, the defer attribute will be useful in ensuring that the HTML is fully parsed before executing.

<!doctype html>
<html>
<head>
<title>Deferred Script</title>
</head>
<body>
<!-- Content before the script -->
<h1>Deferred Script Example</h1>
<p>This content will be rendered before the deferred script executes.</p>
<!-- Deferred script -->
<script defer src="deferred.js"></script>
<!-- Content after the script -->
<p>This content will be rendered before the deferred script executes.</p>
</body>
</html>

Notes

  • The async attribute should be used for scripts that are not critical to the initial rendering of the page and do not depend on each other, while the defer attribute should be used for scripts that depend on / is depended on by another script.
  • The async and defer attributes are ignored for scripts that have no src attribute.
  • <script>s with defer or async that contain document.write() will be ignored with a message like "A call to document.write() from an asynchronously-loaded external script was ignored".
  • Even though async and defer help to make script downloading asynchronous, the scripts are still eventually executed on the main thread. If these scripts are computationally intensive, it can result in laggy/frozen UI. Partytown is a library that helps relocate script executions into a web worker and off the main thread, which is great for third-party scripts where you do not have control over the code.

Further reading

Why is it generally a good idea to position CSS `<link>`s between `<head></head>` and JS `<script>`s just before `</body>`?

Do you know any exceptions?
Topics
HTMLPerformance

In a nutshell, such a placement of CSS <link>s and JavaScript <script>s allows for faster rendering of the page and better overall performance.

Placing <link>s in <head>

Putting <link>s in <head> is part of the proper specification in building an optimized website. When a page first loads, HTML and CSS are being parsed simultaneously; HTML creates the DOM (Document Object Model) and CSS creates the CSSOM (CSS Object Model). Both are needed to create the visuals in a website, allowing for a quick "first meaningful paint" timing. Placing CSS <link>s in the <head> ensures that the stylesheets are loaded and ready for use when the browser starts rendering the page.

This progressive rendering is a metric that sites are measured on in their performance scores. Putting stylesheets near the bottom of the document is what prohibits progressive rendering in many browsers. Some browsers block rendering to avoid having to repaint elements of the page if their styles change. The user is then stuck viewing a blank white page. Other times there can be flashes of unstyled content (FOUC), which show a webpage with no styling applied.

Placing <script>s just before </body>

<script> tags block HTML parsing while they are being downloaded and executed which can slow down the display of your page. Placing the <script>s at the bottom will allow the HTML to be parsed and displayed to the user first.

An exception for positioning of <script>s at the bottom is when your script contains document.write(), but these days it's not a good practice to use document.write(). Also, placing <script>s at the bottom means that the browser cannot start downloading the scripts until the entire document is parsed. This ensures your code that needs to manipulate DOM elements will not throw an error and halt the entire script. If you need to put <script>s in the <head>, use the defer attribute, which will achieve the same effect of running the script only after the HTML is parsed but the browser can kick off the network request earlier to download the script.

Keep in mind that putting scripts just before the closing </body> tag will create the illusion that the page loads faster on an empty cache (since the scripts won't block downloading the rest of the document). However, if you have some code you want to run during page load, it will only start executing after the entire page has loaded. If you put those scripts in the <head> tag, they would start executing before - so on a primed cache the page would actually appear to load faster.

<head> and <body> tags are now optional

As per the HTML5 specification, certain HTML tags like <head> and <body> are optional. Google's style guide even recommends removing them to save bytes. However, this practice is still not widely adopted and the performance gain is likely to be minimal and for most sites it's not likely going to matter.

Consider HTML5 as an open web platform. What are the building blocks of HTML5?

Topics
BrowserHTML
  • Semantics: HTML tags describe the content.
  • Styling: Customizing appearance of HTML tags
  • Connectivity: Communicate with the server in new and innovative ways.
  • Offline and storage: Allows webpages to store data on the client-side locally and operate offline more efficiently.
  • Multimedia: Makes video and audio first-class citizens in the Open Web.
  • 2D/3D graphics and effects: Allows a much more diverse range of presentation options.
  • Performance and integration: Provides greater speed optimization and better usage of computer hardware.
  • Device access: Allows for the usage of various input and output devices.

What are `data-` attributes good for?

Topics
Web APIsHTMLTesting

Before JavaScript frameworks became popular, developers used data- attributes to store extra data within the DOM itself, without other hacks such as non-standard attributes, extra properties on the DOM. It is intended to store custom data private to the page or application, for when there are no more appropriate attributes or elements.

Another common use case for data- attributes is to store information used by third-party libraries or frameworks. For example, the Bootstrap library uses data attributes to cause <button>s to trigger actions on a modal elsewhere on the page (example).

<button type="button" data-bs-toggle="modal" data-bs-target="#myModal">
Launch modal
</button>
...
<div class="modal fade" id="myModal">Modal contents</div>

These days, using data- attributes is generally not encouraged. One reason is that users can modify the data attribute easily by using "inspect element" in the browser. The data model is better stored within JavaScript environment and have them kept in-sync with the DOM via virtual DOM reconciliation or two-way data binding possibly through a library or a framework.

However, one perfectly valid use of data attributes, is to add an identifier for end-to-end testing frameworks (e.g. Playwright, Puppeteer, Selenium), without adding classes or ID attributes just for tests which are primarily for other purposes. The element needs a way to be selected and something like data-test-id="my-element" is a valid way to do so without convoluting the semantic markup otherwise.

What is progressive rendering?

Topics
HTML

Progressive rendering is the name given to techniques used to improve the performance of a webpage (in particular, improve perceived load time) to render content for display as quickly as possible.

It used to be much more prevalent in the days before broadband internet but it is still used in modern development as mobile data connections are becoming increasingly popular (and unreliable)!

Lazy loading of images

Images on the page are not loaded all at once. The image is only loaded when the user scrolls into/near the part of the page that displays the image.

  • <img loading="lazy"> is a modern way to instruct the browser to defer loading of images that are outside of the screen until the user scrolls near them.
  • Use JavaScript to watch the scroll position and load the image when the image is about to come on screen (by comparing the coordinates of the image with the scroll position).

Prioritizing visible content (or above-the-fold rendering)

Include only the minimum CSS/content/scripts necessary for the amount of page that would be rendered in the users browser first to display as quickly as possible, you can then use deferred scripts or listen for the DOMContentLoaded/load event to load in other resources and content.

Async HTML fragments

Flushing parts of the HTML to the browser as the page is constructed on the back end. More details on the technique can be found here.

Other modern techniques

Why you would use a `srcset` attribute in an image tag?

Explain the process the browser uses when evaluating the content of this attribute.
Topics
HTML

You would use the srcset attribute when you want to serve different images to users depending on their device display width - serve higher quality images to devices with retina display enhances the user experience while serving lower resolution images to low-end devices increase performance and decrease data wastage (because serving a larger image will not have any visible difference). For example: <img srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w" src="..." alt=""> tells the browser to display the small, medium or large .jpg graphic depending on the client's resolution. The first value is the image name and the second is the width of the image in pixels. For a device width of 320px, the following calculations are made:

  • 500 / 320 = 1.5625
  • 1000 / 320 = 3.125
  • 2000 / 320 = 6.25

If the client's resolution is 1x, 1.5625 is the closest, and 500w corresponding to small.jpg will be selected by the browser.

If the resolution is retina (2x), the browser will use the closest resolution above the minimum. Meaning it will not choose the 500w (1.5625) because it is greater than 1 and the image might look bad. The browser would then choose the image with a resulting ratio closer to 2 which is 1000w (3.125).

srcsets solve the problem whereby you want to serve smaller image files to narrow screen devices, as they don't need huge images like desktop displays do — and also optionally that you want to serve different resolution images to high density/low-density screens.

Difference between document `load` event and document `DOMContentLoaded` event?

Topics
HTMLJavaScript

TL;DR

The DOMContentLoaded event fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. The load event, on the other hand, fires when the entire page, including all dependent resources such as stylesheets and images, has finished loading.

document.addEventListener('DOMContentLoaded', function () {
console.log('DOM fully loaded and parsed');
});
window.addEventListener('load', function () {
console.log('Page fully loaded');
});

Difference between document load event and document DOMContentLoaded event

DOMContentLoaded event

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. This event is useful when you want to execute JavaScript code as soon as the DOM is ready, without waiting for all resources to be fully loaded.

document.addEventListener('DOMContentLoaded', function () {
console.log('DOM fully loaded and parsed');
});

load event

The load event is fired when the entire page, including all dependent resources such as stylesheets, images, and subframes, has finished loading. This event is useful when you need to perform actions that require all resources to be fully loaded, such as initializing a slideshow or performing layout calculations that depend on image sizes.

window.addEventListener('load', function () {
console.log('Page fully loaded');
});

Key differences

  • Timing: DOMContentLoaded fires earlier than load. DOMContentLoaded occurs after the HTML is fully parsed, while load waits for all resources to be loaded.
  • Use cases: Use DOMContentLoaded for tasks that only require the DOM to be ready, such as attaching event listeners or manipulating the DOM. Use load for tasks that depend on all resources being fully loaded, such as image-dependent layout calculations.

Further reading

What kind of things must you be wary of when designing or developing for multilingual sites?

Topics
HTMLInternationalization

Designing and developing for multilingual sites is part of internationalization (i18n).

Search Engine Optimization

  • Use the lang attribute on the <html> tag.
  • Include the locale in the URL (e.g en_US, zh_CN, etc).
  • Webpages should use <link rel="alternate" hreflang="other_locale" href="url_for_other_locale"> to tell search engines that there is another page at the specified href with the same content but for another language/locale.
  • Use a fallback page for unmatched languages. Use the "x-default" value: <link rel="alternate" href="url_for_fallback" hreflang="x-default" />.

Understanding the difference between locale vs language

Locale settings control how numbers, dates, and times display for your region: which may be a country, or a portion of country or may not even honor country boundaries.

Language can differ between countries

Certain languages, especially the widely-spoken languages have different "flavors" in different countries (grammar rules, spelling, characters). It's important to differentiate languages for the target country and not assume/force one country's version of a language for all countries which speak the language. Examples:

  • en: en-US (American English), en-GB (British English)
  • zh: zh-CN (Chinese (Simplified)), zh-TW (Chinese (Traditional))

Predict locale but don't restrict

Servers can determine the locale/language of visitors via a combination of HTTP Accept-Language headers and IPs. With these, servers can automatically select the best locale for the visitor. However, predictions are not foolproof (especially if visitors are using VPNs) and visitors should still be allowed to change their country/language easily without hassle.

Consider differences in the length of text in different languages

Some content can be longer when written in another language. Be wary of layout or overflow issues in the design. It's best to avoid designing where the amount of text would make or break a design. Character counts come into play with things like headlines, labels, and buttons. They are less of an issue with free-flowing text such as body text or comments. For example, some languages, such as German and French, tend to use longer words and sentences than English, which can cause layout issues if you do not take this into account.

Language reading direction

Languages like English and French are written from left-to-right, top-to-bottom. However some languages, such as Hebrew and Arabic, are written from right to left. This can affect the layout of your site and the placement of elements on the page, so you must be careful to design your site in a way that accommodates different text directions.

Do not concatenate translated strings

Do not do anything like "The date today is " + date. It will break in languages with different word order. Use a template string with parameters substitution for each language instead. For example, look at the following two sentences in English and Chinese respectively: I will travel on {% date %} and 我会在{% date %}出发. Note that the position of the variable is different due to grammar rules of the language.

Formatting dates and currencies

Calendar dates are sometimes presented in different ways. Eg. "May 31, 2012" in the U.S. vs. "31 May 2012" in parts of Europe.

Do not put text in images

Putting text in raster-based images (e.g. png, gif, jpg, etc.), is not a scalable approach. Placing text in an image is still a popular way to get good-looking, non-system fonts to display on any computer. However, to support image text translation other languages, there needs to be a separate image created for each language which is not a scalable workflow for designers.

Be mindful of how colors are perceived

Colors are perceived differently across languages and cultures. The design should use color appropriately.

References

How do you serve a page with content in multiple languages?

Topics
HTMLInternationalization

Assumption: The question is about how to serve a page with content available in multiple languages and the content within the page should be displayed only in one consistent language.

Serving a page in different languages is one of the aspects of internationalization (i18n).

When an HTTP request is made to a server, the requesting user agent usually sends information about language preferences, such as in the Accept-Language header. The server can then use this information to return a version of the document in the appropriate language if such an alternative is available. The returned HTML document should also declare the lang attribute in the <html> tag, such as <html lang="en">...</html>.

To let a search engine know that the same content is available in different languages, <link> tags with the rel="alternate" and hreflang="..." attributes should be used. E.g. <link rel="alternate" hreflang="de" href="http://de.example.com/page.html" />.

Rendering

  • Server-side rendering: The HTML markup will contain string placeholders and content for the specific language will be fetched from configuration in code or a translation service. The server then dynamically generates the HTML page with content in that particular language.
  • Client-side rendering: The appropriate locale strings will be fetched and combined with the JavaScript-based views.

What does a `DOCTYPE` do?

Topics
HTML

DOCTYPE is an abbreviation for Document Type. A DOCTYPE is always associated to a DTD - for Document Type Definition.

A DTD defines how documents of a certain type should be structured (i.e. a button can contain a span but not a div), whereas a DOCTYPE declares what DTD a document supposedly respects (i.e. this document respects the HTML DTD).

For webpages, the DOCTYPE declaration is required. It is used to tell user agents what version of the HTML specifications your document respects. Once a user agent has recognized a correct DOCTYPE, it will trigger the no-quirks mode matching this DOCTYPE for reading the document. If a user agent doesn't recognize a correct DOCTYPE, it will trigger the quirks mode.

The DOCTYPE declaration for the HTML5 standards is <!DOCTYPE html>.

Explain what a single page app is and how to make one SEO-friendly

Topics
JavaScriptHTML

TL;DR

A single page application (SPA) is a web application that loads a single HTML page and dynamically updates content as the user interacts with the app. This approach provides a more fluid user experience but can be challenging for SEO because search engines may not execute JavaScript to render content. To make an SPA SEO-friendly, you can use server-side rendering (SSR) or static site generation (SSG) to ensure that search engines can index your content. Tools like Next.js for React or Nuxt.js for Vue.js can help achieve this.


What is a single page app?

Definition

A single page application (SPA) is a web application that interacts with the user by dynamically rewriting the current page rather than loading entire new pages from the server. This results in a more fluid user experience, similar to a desktop application.

Key characteristics

  • The application loads a single HTML page and dynamically updates it as the user interacts with the app
  • Uses AJAX or Fetch API to communicate with the server and update the page without a full reload
  • Often relies on client-side routing to manage different views or states within the app

Benefits

  • Faster interactions after the initial load
  • Reduced server load due to fewer full-page requests
  • Improved user experience with smoother transitions

How to make an SPA SEO-friendly

Challenges

SPAs can be challenging for SEO because search engines may not execute JavaScript to render content. This can result in search engines indexing an empty or incomplete page.

Solutions

Server-side rendering (SSR)

Server-side rendering involves rendering the initial HTML of the page on the server before sending it to the client. This ensures that search engines can index the fully rendered content.

  • React: Use Next.js, which provides built-in support for SSR
  • Vue.js: Use Nuxt.js, which also supports SSR out of the box

Example with Next.js:

import React from 'react';
import { GetServerSideProps } from 'next';
const Page = ({ data }) => {
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
};
export const getServerSideProps: GetServerSideProps = async () => {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: {
data,
},
};
};
export default Page;
Static site generation (SSG)

Static site generation involves generating the HTML for each page at build time. This approach is suitable for content that doesn't change frequently.

  • React: Use Next.js with its static generation capabilities
  • Vue.js: Use Nuxt.js with its static site generation feature

Example with Next.js:

import React from 'react';
import { GetStaticProps } from 'next';
const Page = ({ data }) => {
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
};
export const getStaticProps: GetStaticProps = async () => {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: {
data,
},
};
};
export default Page;
Pre-rendering with tools

Some tools can pre-render your SPA and serve the pre-rendered HTML to search engines.

  • Prerender.io: A service that pre-renders your JavaScript application and serves the static HTML to search engines
  • Rendertron: A headless Chrome rendering solution that can be used to pre-render your SPA

Further reading

When would you use `document.write()`?

Topics
Web APIsJavaScriptHTML

TL;DR

document.write() is rarely used in modern web development because it can overwrite the entire document if called after the page has loaded. It is mainly used for simple tasks like writing content during the initial page load, such as for educational purposes or quick debugging. However, it is generally recommended to use other methods like innerHTML, appendChild(), or modern frameworks for manipulating the DOM.


When would you use document.write()?

Initial page load

document.write() can be used to write content directly to the document during the initial page load. This is one of the few scenarios where it might be appropriate, as it can be simpler and faster for very basic tasks.

<!doctype html>
<html>
<head>
<title>Document Write Example</title>
</head>
<body>
<script>
document.write('<h1>Hello, World!</h1>');
</script>
</body>
</html>

Educational purposes

document.write() is sometimes used in educational contexts to demonstrate basic JavaScript concepts. It provides a straightforward way to show how JavaScript can manipulate the DOM.

Quick debugging

For quick and dirty debugging, document.write() can be used to output variables or messages directly to the document. However, this is not recommended for production code.

var debugMessage = 'Debugging message';
document.write(debugMessage);

Legacy code

In some older codebases, you might encounter document.write(). While it's not recommended to use it in new projects, understanding it can be useful for maintaining or refactoring legacy code.

Why not use document.write()?

  • Overwrites the document: If called after the page has loaded, document.write() will overwrite the entire document, which can lead to loss of content and a poor user experience.
  • Better alternatives: Modern methods like innerHTML, appendChild(), and frameworks like React or Vue provide more control and are safer to use.
// Using innerHTML
document.getElementById('content').innerHTML = '<h1>Hello, World!</h1>';
// Using appendChild
var newElement = document.createElement('h1');
newElement.textContent = 'Hello, World!';
document.getElementById('content').appendChild(newElement);

Further reading

What is the difference between `mouseenter` and `mouseover` event in JavaScript and browsers?