display and visibility
Every element has a display value that decides how it sits on the page. Most are block or inline by default.
block and inline
<style>
body { font-family: system-ui; }
div, p { background: #eef0ff; border: 1px solid #5a48f5; }
span, a, strong { background: #fff4dc; border: 1px solid #e0a020; }
</style>
<div>A div is block</div>
<p>A paragraph is block too</p>
<span>A span is inline,</span> <a href="#">so is a link,</a> <strong>and so is strong.</strong>block | inline | |
|---|---|---|
| starts on a new line | yes | no, it flows along with the text |
| width | fills the space available | only as wide as its content |
width and height | work | are ignored |
| vertical margin | pushes neighbours away | has no effect |
| examples | div, p, h1, ul, section | span, a, strong, em, code |
Changing the display
<style>
body { font-family: system-ui; }
.menu a { display: inline-block; padding: 8px 14px; margin: 4px; background: #5a48f5; color: white;
text-decoration: none; border-radius: 6px; }
.stack span { display: block; padding: 6px; border-bottom: 1px solid #ddd; }
</style>
<nav class="menu"><a href="#">Home</a><a href="#">Courses</a><a href="#">About</a></nav>
<div class="stack"><span>Spans made block,</span><span>each on its own line</span></div>inline-block is the middle ground: it sits in a line like text, but accepts width, height, padding and margin like a block. That makes it ideal for buttons and badges.
Three ways to hide something
<style>
body { font-family: system-ui; }
p { margin: 12px 0 4px; }
.row { display: flex; gap: 8px; }
.row div { padding: 14px; background: #eef0ff; border: 2px solid #5a48f5; border-radius: 6px; }
.none .target { display: none; }
.hidden .target { visibility: hidden; }
.faded .target { opacity: 0; }
</style>
<p>display: none, and the gap closes</p>
<div class="row none"><div>A</div><div class="target">B</div><div>C</div></div>
<p>visibility: hidden, and the space stays</p>
<div class="row hidden"><div>A</div><div class="target">B</div><div>C</div></div>
<p>opacity: 0, and the space stays, but try clicking where B was</p>
<div class="row faded"><div>A</div><div class="target" onclick="alert('You clicked the invisible B')">B</div><div>C</div></div>| Takes up space | Can be clicked | Read by screen readers | Animates smoothly | |
|---|---|---|---|---|
display: none | no | no | no | no |
visibility: hidden | yes | no | no | no, it switches |
opacity: 0 | yes | yes | yes | yes |
opacity: 0 is the only one that fades, but an invisible element that can still be clicked and read aloud is a trap. Pair it with visibility: hidden or pointer-events: none once a fade-out has finished.
Showing and hiding with JavaScript
<style>
body { font-family: system-ui; }
.panel { padding: 12px; margin-top: 8px; background: #d9f7ea; border-radius: 8px; }
.panel.is-hidden { display: none; }
</style>
<button id="toggle">Show or hide the details</button>
<div class="panel is-hidden" id="panel">Here are the details.</div>
<script>
document.querySelector("#toggle").addEventListener("click", () => {
document.querySelector("#panel").classList.toggle("is-hidden");
});
</script>Toggling a class keeps the styling in CSS, where it belongs. The HTML hidden attribute (<div hidden>) does the same job as display: none.
The layout values
display also switches on the two big layout systems for an element's children: display: flex and display: grid, which have lessons of their own. inline-flex and inline-grid do the same, while the container itself sits inline.