{"id":774,"date":"2026-02-24T05:34:45","date_gmt":"2026-02-24T05:34:45","guid":{"rendered":"https:\/\/www.cssportal.com\/blog\/?p=774"},"modified":"2026-02-25T07:55:44","modified_gmt":"2026-02-25T07:55:44","slug":"the-difference-between-display-none-visibility-hidden","status":"publish","type":"post","link":"https:\/\/www.cssportal.com\/blog\/the-difference-between-display-none-visibility-hidden\/","title":{"rendered":"The difference between display: none &#038; visibility: hidden"},"content":{"rendered":"<style>\n:root{--ink:#1a1a2e;--paper:#f5f0e8;--accent:#c84b31;--accent2:#3a86ff;--ghost:#9999bb;--mono:'DM Mono', monospace;--serif:'Fraunces', serif;--sans:'DM Sans', sans-serif}.demo-wrapper{background:#fff;border:1px solid #d8d2c6;border-radius:12px;overflow:hidden;margin:28px 0;box-shadow:0 4px 24px rgb(0 0 0 \/ .06)}.demo-header{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f0ebe0;border-bottom:1px solid #d8d2c6;font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:#888}.demo-dots{display:flex;gap:6px}.demo-dots span{width:10px;height:10px;border-radius:50%;background:#ddd}.demo-dots span:nth-child(1){background:#ff6b6b}.demo-dots span:nth-child(2){background:#ffd93d}.demo-dots span:nth-child(3){background:#6bcb77}.demo-stage{padding:32px 28px;display:flex;flex-direction:column;gap:0}.box{padding:18px 22px;border-radius:6px;font-family:var(--mono);font-size:.8rem;font-weight:500;text-align:center;transition:all 0.4s ease}.box-a{background:#3a86ff22;border:2px solid var(--accent2);color:var(--accent2);margin-bottom:12px}.box-b{background:#c84b3122;border:2px dashed var(--accent);color:var(--accent);margin-bottom:12px;position:relative}.box-c{background:#2b62;border:2px solid #2b6;color:#2b6}.ghost-label{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:#1a1a2e;color:#fff;font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;padding:8px 18px;border-radius:4px;white-space:nowrap;box-shadow:0 4px 16px rgb(0 0 0 \/ .35);border:1px solid rgb(255 255 255 \/ .15);z-index:10;animation:pulse 1.8s ease-in-out infinite}@keyframes pulse{0%,100%{box-shadow:0 4px 16px rgb(0 0 0 \/ .35),0 0 0 0 rgb(26 26 46 \/ .4)}50%{box-shadow:0 4px 16px rgb(0 0 0 \/ .35),0 0 0 6px #fff0}}.visibility-ghost{visibility:hidden;opacity:.18;border-style:dashed;filter:grayscale(1)}.display-none{display:none}.toggle-it{width:100%;display:block;align-items:center;gap:8px;margin-top:18px;padding:10px 22px;border:2px solid var(--ink);background:#fff0;font-family:var(--mono);font-size:.78rem;font-weight:500;cursor:pointer;border-radius:4px;transition:all 0.2s;letter-spacing:.05em}.toggle-it:hover{background:var(--ink);color:var(--paper)}.toggle-it.active{background:var(--ink);color:var(--paper)}.gap-indicator{position:relative;height:0;overflow:visible;display:flex;align-items:center;justify-content:center;transition:height 0.4s ease}.gap-indicator.visible{height:56px}.gap-indicator-inner{font-family:var(--mono);font-size:10px;color:#aaa;letter-spacing:.1em;text-transform:uppercase;background:#fff;border:1px dashed #ccc;padding:4px 12px;border-radius:3px;pointer-events:none;white-space:nowrap;transition:opacity 0.3s}table{width:100%;border-collapse:collapse;font-size:.88rem;margin:28px 0;border:1px dashed #ccc}th{font-family:var(--mono);font-size:16px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);text-align:left;padding:10px 14px;border-bottom:2px solid #ddd}td{padding:12px 14px;border-bottom:1px solid #eee;vertical-align:top;line-height:1.5}tr:last-child td{border-bottom:none}td:first-child{font-family:var(--mono);font-size:.82rem;color:var(--accent);width:30%}.yes{color:#2b6;font-weight:500}.no{color:var(--accent);font-weight:500}.callout{border-left:3px solid var(--accent2);background:#3a86ff0d;padding:16px 20px;border-radius:0 8px 8px 0;margin:24px 0;font-size:.92rem}.callout strong{color:var(--accent2);font-family:var(--mono);font-size:1.1em;letter-spacing:.05em}\n<\/style>\n<p>If you&#8217;ve ever needed to hide an element on a page, you&#8217;ve probably reached for one of these two CSS properties. At first glance they seem identical &#8211; the element disappears. But under the hood, they solve the problem in fundamentally different ways, and choosing the wrong one can cause subtle, frustrating layout bugs.<\/p>\n<p>The key distinction: <code>display: none<\/code> removes the element entirely from the document flow, as if it never existed. <code>visibility: hidden<\/code> hides the element visually but <strong>preserves its space<\/strong> in the layout.<\/p>\n<h3 class=\"highlight\">display: none &#8211; gone without a trace<\/h3>\n<p>When you apply <code>display: none<\/code> to an element, the browser completely removes it from the document\u2019s rendering tree. This means the element is not just hidden visually &#8211; it no longer participates in layout calculations at all. The space it would have occupied disappears instantly, so surrounding elements shift to fill the gap as though the element were never present. Margins, padding, and dimensions associated with that element are ignored, and any child elements are also excluded from rendering. Because it is effectively taken out of the flow, the page reflows to accommodate the change, which can affect positioning, alignment, and even performance if large sections of the layout are toggled on and off.<\/p>\n<pre class=\"language-css\"><code>.hidden-box {\r\n  display: none; \/* element is fully removed from flow *\/\r\n}<\/code><\/pre>\n<div class=\"demo-wrapper\">\n<div class=\"demo-header\">\n<div class=\"demo-dots\"><span><\/span><span><\/span><span><\/span><\/div>\n<p>        <span>display: none &#8211; interactive demo<\/span><br \/>\n        <span><\/span>\n      <\/div>\n<div class=\"demo-stage\">\n<div class=\"box box-a\">Box A &#8211; always visible<\/div>\n<div class=\"box box-b\" id=\"displayBox\">Box B &#8211; toggle me<\/div>\n<div class=\"box box-c\">Box C &#8211; always visible<\/div>\n<p>        <button class=\"toggle-it\" id=\"displayBtn\" onclick=\"toggleDisplay()\">Hide Box B with display: none<\/button>\n      <\/div>\n<\/p><\/div>\n<p>Notice how when Box B is hidden, Box C immediately shifts upward to occupy the freed space. Because the hidden element no longer contributes to layout, the browser recalculates positions and closes the gap as if Box B were never there. There\u2019s no reserved placeholder, no invisible footprint left behind &#8211; just a seamless reflow of the surrounding content. This behaviour makes <code>display: none<\/code> especially useful for conditionally rendered interface components such as modals, dropdown menus, tab panels, or expandable sections, where you want elements to appear and disappear without leaving awkward spacing or disrupting the overall structure of the page.<\/p>\n<div class=\"callout\">\n      <strong>Note:<\/strong> Elements with <code>display: none<\/code> are also removed from the accessibility tree and cannot be focused by keyboard navigation.\n    <\/div>\n<div class=\"text-center mb-20 mt-20\">\n<script async src=\"https:\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js\"><\/script>\n<!-- CSS Responsive -->\n<ins class=\"adsbygoogle\"\n     style=\"display:block\"\n     data-ad-client=\"ca-pub-1356719463849900\"\n     data-ad-slot=\"5275015068\"\n     data-ad-format=\"horizontal\"\n     data-full-width-responsive=\"true\"><\/ins>\n<script>\n     (adsbygoogle = window.adsbygoogle || []).push({});\n<\/script>\n<\/div>\n<div class=\"adblock-message bg-main-50 rounded p-10 mb-20\">  \n\t<div class=\"d-flex align-items-center justify-content-between\">\n\t  <span class=\"text-gray-400\">If this site has been useful, we\u2019d love your support! Consider buying us a coffee to keep things going strong!<\/span>\n\t  <div class=\"buymeacoffee\">\n\t\t<a target=\"_blank\" href=\"https:\/\/buymeacoffee.com\/rpjs\"><img decoding=\"async\" width=\"180\" src=\"\/assets\/images\/coffee.png\"><\/a>\n\t  <\/div>\n\t<\/div>\n<\/div>\n<h3 class=\"highlight\">visibility: hidden &#8211; the invisible ghost<\/h3>\n<p><code>visibility: hidden<\/code> hides the element\u2019s visual output while keeping the element itself in the layout. Unlike <code>display: none<\/code>, the browser still calculates its dimensions, margins, and position, so the space it would normally occupy remains reserved. The element becomes invisible rather than removed, almost like a transparent placeholder sitting in the same spot. Because it continues to participate in the document flow, surrounding elements do not shift to fill the gap, which can be useful when you need to temporarily conceal content without affecting alignment or causing layout changes.<\/p>\n<pre class=\"language-css\"><code>.ghost-box {\r\n  visibility: hidden; \/* invisible, but space is preserved *\/\r\n}\r\n\r\n\/* Children can override it! *\/\r\n.ghost-box .child {\r\n  visibility: visible; \/* this child will show through *\/\r\n}<\/code><\/pre>\n<div class=\"demo-wrapper\">\n<div class=\"demo-header\">\n<div class=\"demo-dots\"><span><\/span><span><\/span><span><\/span><\/div>\n<p>        <span>visibility: hidden &#8211; ghost demo<\/span><br \/>\n        <span><\/span>\n      <\/div>\n<div class=\"demo-stage\">\n<div class=\"box box-a\">Box A &#8211; always visible<\/div>\n<div id=\"visibilityBox\" class=\"box box-b\" style=\"position:relative;\">\n          <span class=\"ghost-label\" id=\"ghostLabel\" style=\"display:none;\">\ud83d\udc7b space preserved<\/span>Box B &#8211; toggle me\n        <\/div>\n<div class=\"box box-c\">Box C &#8211; always visible<\/div>\n<p>        <button class=\"toggle-it\" id=\"visibilityBtn\" onclick=\"toggleVisibility1()\">Hide Box B with visibility: hidden<\/button>\n      <\/div>\n<\/p><\/div>\n<p>See it? Box B disappears from view, yet the space it occupied is still preserved &#8211; Box C remains anchored in the same position. Because the element is only made invisible rather than removed, the browser keeps its dimensions in the layout, preventing any reflow or sudden movement of surrounding content. This results in a stable, non-jumping interface, which can be particularly helpful when toggling temporary states, preparing content for animations, or hiding elements that are expected to reappear quickly without disrupting the user\u2019s sense of spatial continuity.<\/p>\n<div class=\"callout\">\n      <strong>Bonus trick:<\/strong> Unlike <code>display: none<\/code>, you can override <code>visibility: hidden<\/code> on child elements by setting <code>visibility: visible<\/code> on them. Child elements can &#8220;show through&#8221; a hidden parent.\n    <\/div>\n<h3 class=\"highlight\">Side-by-side comparison<\/h3>\n<p>Here&#8217;s a quick reference for the key differences:<\/p>\n<table>\n<thead>\n<tr>\n<th>Property<\/th>\n<th>display: none<\/th>\n<th>visibility: hidden<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Preserves layout space<\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<td><span class=\"yes\">\u2713 Yes<\/span><\/td>\n<\/tr>\n<tr>\n<td>Visible on screen<\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<\/tr>\n<tr>\n<td>Accessible to screen readers<\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<td><span class=\"no\">\u2717 No (usually)<\/span><\/td>\n<\/tr>\n<tr>\n<td>Receives pointer events<\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<\/tr>\n<tr>\n<td>Children can override<\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<td><span class=\"yes\">\u2713 Yes<\/span><\/td>\n<\/tr>\n<tr>\n<td>Animatable with CSS transitions<\/td>\n<td><span class=\"no\">\u2717 Not directly<\/span><\/td>\n<td><span class=\"yes\">\u2713 Yes<\/span><\/td>\n<\/tr>\n<tr>\n<td>Triggers layout reflow<\/td>\n<td><span class=\"yes\">\u2713 Yes (on toggle)<\/span><\/td>\n<td><span class=\"no\">\u2717 No<\/span><\/td>\n<\/tr>\n<tr>\n<td>Common use case<\/td>\n<td>Modals, tabs, conditional UI<\/td>\n<td>Stable layouts, fade-in animations<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 class=\"highlight\">Which one should you use?<\/h3>\n<p>\n      Use <code>display: none<\/code> when you want the element to genuinely not take up space &#8211; conditional rendering, toggleable panels, menu items, and anything where reflowing the layout is acceptable or desired.\n    <\/p>\n<p>\n      Use <code>visibility: hidden<\/code> when you need the space to be held in place &#8211; for example, when you&#8217;re fading an element in and out and don&#8217;t want the surrounding content to jump around. It&#8217;s also handy when building skeleton loaders or placeholder layouts.\n    <\/p>\n<p>\n      For smooth fade animations, a common pattern combines both:\n    <\/p>\n<pre class=\"language-css\"><code>.fade-element {\r\n  visibility: visible;\r\n  opacity: 1;\r\n  transition: opacity 0.3s ease, visibility 0.3s;\r\n}\r\n\r\n.fade-element.hidden {\r\n  visibility: hidden;\r\n  opacity: 0;\r\n  \/* opacity animates smoothly; visibility snaps at the end *\/\r\n}<\/code><\/pre>\n<p>\n      This lets the opacity transition animate, while <code>visibility: hidden<\/code> ensures the element becomes fully non-interactive at the end of the transition (unlike <code>opacity: 0<\/code> alone, which is invisible but still clickable).\n    <\/p>\n<h3 class=\"highlight\">Dig deeper<\/h3>\n<p>\n    Now that you understand the difference, it&#8217;s worth exploring the full picture. The <a href=\"\/css-properties\/display.php\">display<\/a> property goes far beyond <code>none<\/code> &#8211; it&#8217;s the foundation of Flexbox and Grid. And the <a href=\"\/css-properties\/visibility.php\">visibility<\/a> property has a third value, <code>collapse<\/code>, which behaves specially inside tables and subgrids. If you&#8217;re reaching for <code>visibility: hidden<\/code> just to stop clicks, you might also want <a href=\"\/css-properties\/pointer-events.php\">pointer-events<\/a>. And if smooth fade-outs are your goal, <a href=\"\/css-properties\/opacity.php\">opacity<\/a> paired with <a href=\"\/css-properties\/visibility.php\">visibility<\/a> is the go-to pattern.\n  <\/p>\n<p><script>\nlet displayHidden=!1;let visibilityHidden=!1;function toggleDisplay(){displayHidden=!displayHidden;const box=document.getElementById('displayBox');const btn=document.getElementById('displayBtn');if(displayHidden){box.style.display='none';btn.textContent='Show Box B (restore display)';btn.classList.add('active')}else{box.style.display='';btn.textContent='Hide Box B with display: none';btn.classList.remove('active')}}\nfunction toggleVisibility1(){visibilityHidden=!visibilityHidden;const box=document.getElementById('visibilityBox');const btn=document.getElementById('visibilityBtn');const label=document.getElementById('ghostLabel');if(visibilityHidden){box.style.visibility='hidden';box.style.opacity='0.5';box.style.borderStyle='dashed';label.style.display='block';label.style.visibility='visible';btn.textContent='Show Box B (restore visibility)';btn.classList.add('active')}else{box.style.visibility='';box.style.opacity='';box.style.filter='';box.style.borderStyle='';label.style.display='none';btn.textContent='Hide Box B with visibility: hidden';btn.classList.remove('active')}}\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve ever needed to hide an element on a page, you&#8217;ve probably reached for one of these two CSS properties. At first glance they seem identical &#8211; the element disappears. But under the hood, they solve the problem in fundamentally different ways, and choosing the wrong one can cause subtle, frustrating layout bugs. The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":775,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-css","wpautop"],"_links":{"self":[{"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/posts\/774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/comments?post=774"}],"version-history":[{"count":2,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/posts\/774\/revisions"}],"predecessor-version":[{"id":777,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/posts\/774\/revisions\/777"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/media\/775"}],"wp:attachment":[{"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/media?parent=774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/categories?post=774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cssportal.com\/blog\/wp-json\/wp\/v2\/tags?post=774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}