Display Property & Visual Formatting Model
Understanding the Visual Formatting Model
The CSS visual formatting model is the system the browser uses to process and lay out your document for visual display. When a browser renders an HTML document, it creates a box for every element on the page. Each box has content, padding, borders, and margins. How those boxes are sized, positioned, and arranged relative to each other depends largely on the display property. Understanding the display property and the visual formatting model is fundamental to mastering CSS layout -- it determines how elements flow on the page, how they interact with siblings, and how they respond to width, height, padding, and margin.
Every element in HTML has a default display value assigned by the browser's user-agent stylesheet. Most elements fall into one of two categories: block-level or inline. However, CSS provides many more display values that give you precise control over how elements behave in the layout.
Block-Level Elements
Block-level elements are the structural workhorses of HTML. By default, a block-level element starts on a new line and stretches to fill the full width of its containing element. Block elements stack vertically, one on top of another, creating the natural top-to-bottom flow of a document. Common block-level elements include <div>, <p>, <h1> through <h6>, <section>, <article>, <header>, <footer>, <ul>, <ol>, and <li>.
Key characteristics of block-level elements:
- They always start on a new line, regardless of the remaining space on the current line.
- They expand to fill 100% of the width of their parent container by default.
- You can set explicit
widthandheightvalues on them. - Vertical margins (
margin-topandmargin-bottom) work as expected. - Horizontal margins (
margin-leftandmargin-right) work as expected, andmargin: 0 autocan be used for horizontal centering. - Padding works in all four directions and affects the element's total size.
- Adjacent vertical margins collapse -- the larger margin wins rather than both being applied.
Example: Block-Level Element Behavior
<style>
.block-demo div {
background-color: #e3f2fd;
border: 2px solid #1976d2;
padding: 16px;
margin-bottom: 8px;
}
.narrow-block {
width: 300px;
/* Even with a width set, the element still starts on a new line */
}
</style>
<div class="block-demo">
<div>I am a block element. I take up the full width.</div>
<div>I start on a new line below the first block.</div>
<div class="narrow-block">I have width: 300px but still start on a new line.</div>
<div>The remaining space next to the narrow block is empty.</div>
</div>
Inline Elements
Inline elements flow within the text content of a document. They do not start on a new line -- instead, they sit beside other inline elements and text on the same line, flowing from left to right (in left-to-right languages) and wrapping to the next line only when the available width is exhausted. Common inline elements include <span>, <a>, <strong>, <em>, <code>, <img>, <br>, and <input>.
Key characteristics of inline elements:
- They do not start on a new line -- they flow inline with surrounding text and elements.
- Setting
widthandheighthas no effect on non-replaced inline elements. - Horizontal padding (
padding-leftandpadding-right) works and affects layout. - Vertical padding (
padding-topandpadding-bottom) is applied visually but does not push other lines away -- it may overlap adjacent content. - Horizontal margins (
margin-leftandmargin-right) work as expected. - Vertical margins (
margin-topandmargin-bottom) have no effect on non-replaced inline elements. - The element's size is determined entirely by its content.
Example: Inline Element Behavior
<style>
.inline-demo span {
background-color: #fff3e0;
border: 2px solid #e65100;
padding: 4px 8px;
margin: 20px 8px; /* Only horizontal margins apply */
}
.inline-no-effect {
width: 500px; /* No effect on inline elements */
height: 200px; /* No effect on inline elements */
}
</style>
<p class="inline-demo">
This is normal text with
<span>an inline span</span>
that flows within the paragraph.
<span class="inline-no-effect">Width and height are ignored.</span>
The text continues on the same line.
</p>
margin-top or margin-bottom to an inline element and expecting it to push elements away vertically. These vertical margins are simply ignored for inline elements. If you need vertical spacing on an element that flows inline, consider using display: inline-block instead.Inline-Block: The Hybrid Approach
The display: inline-block value combines characteristics of both block and inline elements. An inline-block element flows inline with surrounding content (like an inline element) but accepts width, height, and vertical margin/padding (like a block element). This makes it extremely useful for creating horizontal layouts of sized boxes without resorting to floats or Flexbox.
Key characteristics of inline-block elements:
- They flow inline -- they sit next to other inline or inline-block elements on the same line.
- You can set explicit
widthandheightvalues. - Vertical margins and padding work correctly and affect surrounding layout.
- They respect
text-alignon the parent element for horizontal positioning. - They are affected by whitespace in the HTML source (whitespace between elements creates small gaps).
- They align vertically with surrounding text using
vertical-align.
Example: Inline-Block for Navigation and Cards
<style>
/* Horizontal navigation using inline-block */
.nav-inline a {
display: inline-block;
padding: 12px 24px;
background-color: #1976d2;
color: white;
text-decoration: none;
border-radius: 4px;
margin-right: 4px;
}
/* Card layout using inline-block */
.card-grid {
text-align: center; /* Centers the inline-block children */
font-size: 0; /* Removes whitespace gaps between inline-block elements */
}
.card-grid .card {
display: inline-block;
width: 250px;
vertical-align: top;
text-align: left;
font-size: 16px; /* Restore font size */
margin: 8px;
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
}
</style>
<nav class="nav-inline">
<a href="#">Home</a>
<a href="#">About</a>
<a href="#">Services</a>
<a href="#">Contact</a>
</nav>
<div class="card-grid">
<div class="card">Card 1 content here</div>
<div class="card">Card 2 with more content that wraps to multiple lines</div>
<div class="card">Card 3 content</div>
</div>
font-size: 0 technique on the parent removes these gaps, but you must remember to restore the font size on the children. Other techniques include removing whitespace from the HTML source, using negative margins, or -- the modern solution -- switching to Flexbox, which does not have this problem.display: none vs visibility: hidden vs opacity: 0
There are three common ways to hide elements in CSS, and each behaves differently in terms of layout, accessibility, and interactivity. Understanding these differences is crucial for implementing features like dropdown menus, modals, tabs, and conditional content.
display: none-- Completely removes the element from the layout. It takes up no space, is invisible, and is removed from the accessibility tree. Screen readers cannot access it. The element does not respond to events.visibility: hidden-- Hides the element visually but it still takes up space in the layout. The invisible element occupies its normal position and size, leaving a visible gap. It is removed from the accessibility tree. The element does not respond to most events (but its space still blocks clicks on elements behind it).opacity: 0-- Makes the element fully transparent but it still takes up space in the layout and remains in the accessibility tree. The element can still receive clicks and other events. Screen readers can still access it.
Example: Comparing Hidden Element Techniques
<style>
.container {
display: flex;
gap: 10px;
padding: 20px;
background-color: #f5f5f5;
}
.box {
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
.box-a { background-color: #e74c3c; }
.box-b { background-color: #3498db; }
.box-c { background-color: #2ecc71; }
/* display: none -- element is completely removed from layout */
.hidden-display { display: none; }
/* visibility: hidden -- element is invisible but holds its space */
.hidden-visibility { visibility: hidden; }
/* opacity: 0 -- element is transparent but still interactive */
.hidden-opacity { opacity: 0; }
</style>
<!-- display: none example -->
<div class="container">
<div class="box box-a">A</div>
<div class="box box-b hidden-display">B</div>
<div class="box box-c">C</div>
<!-- Box C moves next to A. No gap where B was. -->
</div>
<!-- visibility: hidden example -->
<div class="container">
<div class="box box-a">A</div>
<div class="box box-b hidden-visibility">B</div>
<div class="box box-c">C</div>
<!-- There is a visible gap where B is. C stays in place. -->
</div>
<!-- opacity: 0 example -->
<div class="container">
<div class="box box-a">A</div>
<div class="box box-b hidden-opacity">B</div>
<div class="box box-c">C</div>
<!-- Gap exists like visibility:hidden, but B is still clickable. -->
</div>
When choosing between these techniques, consider your requirements: use display: none when the element should be completely absent from the layout and inaccessible; use visibility: hidden when you need to preserve the layout space but hide the element; use opacity: 0 when you want smooth fade transitions (since opacity is animatable but display and visibility are not smoothly transitioned).
display: contents
The display: contents value is a unique and sometimes confusing display type. When applied to an element, it causes that element's box to disappear from the layout -- as if the element itself does not exist -- while its children are promoted up and laid out as if they were direct children of the element's parent. The element still exists in the DOM and the accessibility tree, but it generates no box of its own.
Example: display: contents in Action
<style>
.flex-parent {
display: flex;
gap: 16px;
padding: 16px;
background-color: #f0f0f0;
}
.wrapper {
display: contents;
/* This wrapper generates no box.
Its children become flex items of .flex-parent */
}
.item {
padding: 16px;
background-color: #3498db;
color: white;
border-radius: 8px;
}
</style>
<div class="flex-parent">
<div class="item">Direct Child 1</div>
<div class="wrapper">
<div class="item">Wrapped Child 2</div>
<div class="item">Wrapped Child 3</div>
</div>
<div class="item">Direct Child 4</div>
</div>
<!-- All four .item elements are laid out as flex items,
even though two of them are nested inside .wrapper.
The .wrapper div generates no box. -->
This is particularly useful when you need a semantic wrapper element (for accessibility or JavaScript) but do not want it to interfere with a parent's flex or grid layout. A common use case is wrapping groups of grid items in a semantic element like <section> without breaking the grid layout.
display: contents and accessibility. While the specification says the element should remain in the accessibility tree, some browsers historically removed elements with display: contents from the accessibility tree, especially for elements like <button> and <a>. Modern browsers have largely fixed this, but test thoroughly with screen readers if accessibility is critical.display: flow-root -- The Modern Clearfix
The display: flow-root value creates a new block formatting context (BFC) for the element. This is the modern, clean solution to two classic CSS problems: containing floated children (the old "clearfix" hack) and preventing margin collapse across boundaries.
Example: flow-root to Contain Floats
<style>
/* Problem: Parent collapses when children are floated */
.broken-container {
background-color: #e3f2fd;
border: 2px solid #1976d2;
padding: 16px;
/* Without flow-root, this container collapses to 0 height */
}
.broken-container img {
float: left;
margin-right: 16px;
}
/* Solution: flow-root creates a new BFC that contains floats */
.fixed-container {
display: flow-root; /* This is the modern clearfix */
background-color: #e8f5e9;
border: 2px solid #4caf50;
padding: 16px;
}
.fixed-container img {
float: left;
margin-right: 16px;
}
</style>
<!-- This container collapses -- the background and border shrink -->
<div class="broken-container">
<img src="photo.jpg" alt="Example" width="150" height="150">
<p>This text wraps around the floated image, but the parent
container does not wrap around the float.</p>
</div>
<!-- This container properly contains the float -->
<div class="fixed-container">
<img src="photo.jpg" alt="Example" width="150" height="150">
<p>This text wraps around the floated image, and the parent
container properly expands to contain everything.</p>
</div>
Before display: flow-root existed, developers used various "clearfix" hacks involving ::after pseudo-elements with clear: both, or overflow: hidden on the parent. The display: flow-root value is semantically clearer -- it explicitly says "this element establishes a new formatting context" without the side effects of other methods.
Block Formatting Context (BFC)
A Block Formatting Context (BFC) is a region of the page in which block-level boxes are laid out. It is one of the most important concepts in the visual formatting model. A BFC acts as a self-contained layout environment -- floats, margins, and other layout behaviors are contained within it and do not leak out to affect surrounding elements.
A new BFC is created by any of the following conditions:
- The root element of the document (
<html>) - Floated elements (
floatis notnone) - Absolutely or fixed positioned elements (
position: absoluteorposition: fixed) display: inline-blockdisplay: flow-rootdisplay: flexordisplay: inline-flex(the flex container itself creates a BFC)display: gridordisplay: inline-grid(the grid container creates a BFC)overflowset to anything other thanvisibleorclip(such asauto,scroll, orhidden)display: table-cell,display: table-captioncontain: layout,contain: content, orcontain: paint- Multicol containers (
column-countorcolumn-widthis notauto)
Why BFCs matter:
- Containing floats: A BFC contains all floated descendants, preventing parent collapse.
- Preventing margin collapse: Margins of elements in different BFCs do not collapse into each other.
- Excluding floats: A BFC element placed next to a float will not overlap the float -- it will shrink to fit the remaining space.
Example: BFC Preventing Margin Collapse
<style>
.parent {
background-color: #f5f5f5;
padding: 1px; /* Without this or a BFC, child margins collapse through the parent */
}
/* Without BFC -- margins collapse */
.no-bfc .child {
margin: 30px 0;
padding: 20px;
background-color: #e3f2fd;
}
/* With BFC -- margins are contained */
.with-bfc {
display: flow-root; /* Creates BFC */
}
.with-bfc .child {
margin: 30px 0;
padding: 20px;
background-color: #e8f5e9;
}
</style>
<!-- Without BFC: Top/bottom margins of .child collapse through .parent -->
<div class="parent no-bfc">
<div class="child">Child with 30px margin</div>
</div>
<!-- With BFC: Margins are contained within the parent -->
<div class="parent with-bfc">
<div class="child">Child with 30px margin</div>
</div>
Anonymous Boxes
Anonymous boxes are boxes that the browser creates automatically when text or content exists alongside block-level elements without being wrapped in an element of its own. Understanding anonymous boxes helps explain some unexpected layout behaviors.
Example: Anonymous Box Creation
<div>
This text creates an anonymous block box.
<p>This is a regular paragraph block box.</p>
This text also creates an anonymous block box.
</div>
<!-- The browser internally creates something like this:
<div>
[anonymous block box] This text creates an anonymous block box. [/anonymous block box]
<p>This is a regular paragraph block box.</p>
[anonymous block box] This text also creates an anonymous block box. [/anonymous block box]
</div>
-->
<!-- Similarly for inline contexts: -->
<p>
Some text <em>emphasized text</em> more text.
</p>
<!-- "Some text " and " more text." are wrapped in anonymous inline boxes -->
Anonymous block boxes are created when block-level and inline-level content are mixed as siblings inside a container. The inline content gets wrapped in anonymous block boxes so that all children of the container are at the same level (all block-level). You cannot style anonymous boxes directly because they have no selector, but they inherit styles from their parent element.
Replaced Elements
Replaced elements are elements whose content is not directly represented by the document's CSS box model. Instead, they display external content determined by the element's source or type. The most common replaced elements are <img>, <video>, <iframe>, <input>, <textarea>, <select>, and <canvas>.
Replaced elements have special behavior:
- They have intrinsic dimensions (a natural width and height derived from their content, such as an image's pixel dimensions).
- Even when inline (like
<img>), they can acceptwidthandheightproperties -- unlike non-replaced inline elements. - They have their own rendering rules independent of the CSS box model.
- They support the
object-fitandobject-positionproperties for controlling how their content fills the box.
Example: Replaced Element Behavior
<style>
/* Images are inline by default but accept width/height */
.img-demo img {
width: 200px;
height: 150px;
object-fit: cover; /* Maintains aspect ratio while filling the box */
border-radius: 8px;
}
/* Compare with a span -- non-replaced inline element */
.span-demo span {
width: 200px; /* This has NO effect */
height: 150px; /* This has NO effect */
background-color: #fff3e0;
border: 1px solid #e65100;
}
/* Video element with object-fit */
.video-box {
width: 400px;
height: 225px;
object-fit: contain; /* Fits within the box, may letterbox */
background-color: #000;
}
</style>
<div class="img-demo">
<img src="photo.jpg" alt="A landscape photo cropped to cover 200x150">
</div>
<div class="span-demo">
<span>Width and height are ignored on me.</span>
</div>
Normal Flow
Normal flow is the default layout mode for elements in a document. When elements are in normal flow, block-level elements stack vertically from top to bottom, and inline elements flow horizontally from left to right (in LTR languages), wrapping to the next line when they run out of horizontal space. Elements are only removed from normal flow when you apply float, position: absolute, position: fixed, or position: sticky (partially) to them.
Understanding normal flow is important because all other layout methods (Flexbox, Grid, absolute positioning) are deviations from normal flow. You should always start with normal flow and only break out of it when you have a specific layout need that normal flow cannot address. Well-structured HTML in normal flow is the most accessible and predictable foundation for your layouts.
Formatting Contexts
A formatting context is the environment that determines how child elements are laid out. There are several types of formatting contexts in CSS:
- Block Formatting Context (BFC): Block-level boxes are laid out vertically. We covered this in detail above.
- Inline Formatting Context (IFC): Inline-level boxes are laid out horizontally in line boxes. Text and inline elements participate in an IFC.
- Flex Formatting Context: Created by
display: flexordisplay: inline-flex. Children become flex items and are laid out according to the flex layout algorithm. - Grid Formatting Context: Created by
display: gridordisplay: inline-grid. Children become grid items and are placed within a defined grid. - Table Formatting Context: Created by
display: tableand related values. Children are laid out using the table layout algorithm.
The formatting context a child participates in is determined by the parent's display value. When you set display: flex on a container, all its children are placed in a flex formatting context, regardless of whether those children are <div>, <span>, or any other element.
display: list-item
The display: list-item value makes an element behave like a list item -- it generates a block box for the content and an additional marker box for the bullet or number. This is the default display value for <li> elements. You can use it on other elements to give them list-like behavior, including the ability to show bullets or numbers using list-style-type.
Example: display: list-item on Non-List Elements
<style>
.custom-list div {
display: list-item;
list-style-type: disc;
margin-left: 20px;
padding: 4px 0;
}
.numbered-items p {
display: list-item;
list-style-type: decimal;
margin-left: 24px;
padding: 4px 0;
}
.custom-marker div {
display: list-item;
list-style-type: "→ ";
margin-left: 16px;
padding: 4px 0;
}
</style>
<!-- Regular divs displayed as list items -->
<div class="custom-list">
<div>First item using a div</div>
<div>Second item using a div</div>
<div>Third item using a div</div>
</div>
<!-- Paragraphs displayed as numbered list items -->
<div class="numbered-items">
<p>Step one: Open the editor.</p>
<p>Step two: Write the code.</p>
<p>Step three: Test the result.</p>
</div>
<!-- Custom string markers -->
<div class="custom-marker">
<div>Navigate to Settings</div>
<div>Click on Appearance</div>
<div>Choose your theme</div>
</div>
display: table and Related Values
Before Flexbox and Grid, the display: table family of values was one of the few ways to achieve certain layouts in CSS. These values make non-table elements behave as if they were HTML table elements. While modern layout techniques have largely replaced this approach, understanding table display values is still valuable because they solve certain problems elegantly, such as vertical centering and equal-height columns.
The table display family includes:
display: table-- Behaves like<table>display: table-row-- Behaves like<tr>display: table-cell-- Behaves like<td>display: table-header-group-- Behaves like<thead>display: table-footer-group-- Behaves like<tfoot>display: table-row-group-- Behaves like<tbody>display: table-caption-- Behaves like<caption>display: table-column-- Behaves like<col>display: table-column-group-- Behaves like<colgroup>
Example: Equal-Height Columns with Table Display
<style>
.table-layout {
display: table;
width: 100%;
border-spacing: 16px;
}
.table-row {
display: table-row;
}
.table-cell {
display: table-cell;
padding: 24px;
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 8px;
vertical-align: top;
}
/* All cells in the same row automatically have equal height */
</style>
<div class="table-layout">
<div class="table-row">
<div class="table-cell">
<h3>Column 1</h3>
<p>Short content.</p>
</div>
<div class="table-cell">
<h3>Column 2</h3>
<p>This column has much more content, demonstrating that all
columns in the same row will stretch to match the height of
the tallest column. This is the natural behavior of table
cells and one of the key advantages of table display.</p>
</div>
<div class="table-cell">
<h3>Column 3</h3>
<p>Medium content here.</p>
</div>
</div>
</div>
display: table for layout is not the same as using HTML <table> elements for layout. The CSS approach applies table layout behavior without the semantic implications. Screen readers will not interpret display: table elements as data tables. However, for most modern layouts, Flexbox and Grid are preferred because they offer more flexibility and power.Practical Example: Vertical Centering with Table-Cell
One classic use of display: table-cell is vertical centering. Before Flexbox made align-items: center easy, the table-cell approach was one of the most reliable methods for vertically centering content of unknown height.
Example: Vertical Centering Techniques
<style>
/* Method 1: Table-cell vertical centering */
.center-table {
display: table;
width: 100%;
height: 300px;
}
.center-table-cell {
display: table-cell;
vertical-align: middle;
text-align: center;
background-color: #e3f2fd;
}
/* Method 2: Flexbox centering (modern approach) */
.center-flex {
display: flex;
align-items: center;
justify-content: center;
height: 300px;
background-color: #e8f5e9;
}
/* Method 3: Grid centering (most concise) */
.center-grid {
display: grid;
place-items: center;
height: 300px;
background-color: #fff3e0;
}
/* Method 4: Absolute positioning + transform */
.center-absolute {
position: relative;
height: 300px;
background-color: #fce4ec;
}
.center-absolute .content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<!-- Table-cell approach -->
<div class="center-table">
<div class="center-table-cell">
<p>Vertically and horizontally centered with table-cell.</p>
</div>
</div>
<!-- Flexbox approach -->
<div class="center-flex">
<p>Centered with Flexbox.</p>
</div>
<!-- Grid approach -->
<div class="center-grid">
<p>Centered with Grid.</p>
</div>
<!-- Absolute positioning approach -->
<div class="center-absolute">
<div class="content">
<p>Centered with absolute positioning and transform.</p>
</div>
</div>
display: flex with align-items: center and justify-content: center) or Grid (display: grid with place-items: center) for centering. These modern approaches are simpler, more flexible, and widely supported in all current browsers. The table-cell and absolute positioning methods are worth knowing for legacy code and edge cases.Practical Example: Horizontal Centering Techniques for Block Elements
Centering block-level elements horizontally is a fundamental CSS task. Here are the main approaches and when to use each one:
Example: Multiple Horizontal Centering Methods
<style>
/* Method 1: Auto margins -- for single block elements */
.center-margin {
width: 400px;
margin-left: auto;
margin-right: auto;
padding: 20px;
background-color: #e3f2fd;
border: 1px solid #1976d2;
}
/* Method 2: text-align -- for inline and inline-block children */
.center-text-align {
text-align: center;
}
.center-text-align .box {
display: inline-block;
padding: 20px 40px;
background-color: #e8f5e9;
border: 1px solid #4caf50;
}
/* Method 3: Flexbox -- for any children */
.center-flexbox {
display: flex;
justify-content: center;
}
.center-flexbox .box {
padding: 20px 40px;
background-color: #fff3e0;
border: 1px solid #e65100;
}
/* Method 4: Grid -- for any children */
.center-grid-h {
display: grid;
justify-items: center;
}
.center-grid-h .box {
padding: 20px 40px;
background-color: #fce4ec;
border: 1px solid #c62828;
}
</style>
<!-- Auto margins -->
<div class="center-margin">Centered with margin: auto</div>
<!-- text-align: center -->
<div class="center-text-align">
<div class="box">Centered with text-align</div>
</div>
<!-- Flexbox -->
<div class="center-flexbox">
<div class="box">Centered with Flexbox</div>
</div>
<!-- Grid -->
<div class="center-grid-h">
<div class="box">Centered with Grid</div>
</div>
Summary: The Display Property Quick Reference
Here is a summary of all the display values covered in this lesson and when to use each one:
display: block-- Element takes full width, starts on new line. Use for structural containers and sections.display: inline-- Element flows with text, no width/height control. Use for text-level semantics.display: inline-block-- Flows inline but accepts dimensions. Use for horizontal layouts of sized boxes.display: none-- Completely removes element from layout and accessibility tree. Use to conditionally hide content.display: contents-- Box disappears, children are promoted. Use to unwrap semantic elements in flex/grid layouts.display: flow-root-- Creates new BFC. Use to contain floats and prevent margin collapse.display: list-item-- Generates a marker box. Use for custom list-like elements.display: table,table-cell,table-row-- Table layout behavior. Use for equal-height columns and vertical centering in legacy code.display: flex-- One-dimensional flex layout. Covered in a dedicated lesson.display: grid-- Two-dimensional grid layout. Covered in a dedicated lesson.
Exercise 1: Display Property Exploration
Create an HTML page that demonstrates the differences between block, inline, inline-block, and none. Build four sections, each containing a parent container with a colored background and three child elements. In the first section, set the children to display: block and give each one a width of 200px, a height of 60px, a background color, and margins. Observe how they stack vertically. In the second section, set the children to display: inline and apply the same width, height, and margins. Notice how width and height are ignored and vertical margins have no effect. In the third section, set the children to display: inline-block with the same properties. Note how they flow horizontally while respecting all dimensions and margins. In the fourth section, hide the second child using each of the three hiding methods (display: none, visibility: hidden, and opacity: 0) one at a time, and document the differences in layout and interactivity for each approach. Add a JavaScript button that toggles between the three hiding methods so you can see the differences in real time.
Exercise 2: Build a Layout Using Only Display Properties
Without using Flexbox or Grid, build a complete page layout using only the display property and the techniques covered in this lesson. Create a page with a centered header (max-width 1000px, horizontally centered with auto margins), a horizontal navigation bar built with display: inline-block links, a main content area with a sidebar layout using display: table and display: table-cell for equal-height columns, a card grid using display: inline-block cards with the whitespace gap removed, and a footer. Use display: flow-root on at least one container to clear a floated element. Include a section where you use display: contents to unwrap a semantic wrapper. Add at least one element that can be toggled between display: none and display: block using a JavaScript button. Finally, add display: list-item to a set of <div> elements to create a styled list without using <ul> or <ol>. Test the layout in at least two different browsers to ensure consistent behavior.