admin管理员组

文章数量:1124648

I created a side navigation bar and a main content area. I arranged these in a grid layout using display: grid with columns set to 200px. I also wrote a JavaScript script to toggle the class list. When I click the toggle button, the side navigation shrinks, but the main content area maintains the same width. How can I make the main content area fill the full width?

function toggleSidebar() {
    const sidebar = document.querySelector('.sidebar');
    sidebar.classList.toggle('shrink');
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    height: 100vh;
}

.container {
    display: grid;
    grid-template-columns: 200px minmax(0,1fr); /* Sidebar takes 200px, main content takes remaining space */
    height: 100%;
    grid-template-rows: 1fr; /* Only one row for this layout */
}

.sidebar {
    background-color: #333;
    color: white;
    padding: 15px;
    overflow: hidden;
    transition: width 0.3s ease-in-out; /* Transition effect for shrinking */
}

.sidebar ul {
    list-style-type: none;
}

.sidebar ul li {
    margin-bottom: 10px;
}

.sidebar ul li a {
    color: white;
    text-decoration: none;
}

.main-content {
    background-color: red;
    padding: 20px;
    overflow: auto;
}

.sidebar.shrink {
    width: 50px; /* Shrinks the sidebar width to 50px */
}

.sidebar.shrink ul {
    display: none; /* Hide the links when the sidebar is shrunk */
}

.main-content {
    transition: margin-left 0.3s ease-in-out; /* Adjust content area when sidebar shrinks */
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Grid Layout</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
   <button onclick="toggleSidebar()">Toggle Sidebar</button>
    <div class="container">
        <nav class="sidebar">
            <!-- Side Navigation Content -->
            <ul>
                <li><a href="#">Home</a></li>
                <li><a href="#">About</a></li>
                <li><a href="#">Services</a></li>
                <li><a href="#">Contact</a></li>
            </ul>
        </nav>
        <main class="main-content">
            <!-- Main Content Area -->
            <h1>Welcome to the main content area</h1>
            <p>This area should adjust its size based on the sidebar.</p>
        </main>
    </div>
 

</body>
</html>

I created a side navigation bar and a main content area. I arranged these in a grid layout using display: grid with columns set to 200px. I also wrote a JavaScript script to toggle the class list. When I click the toggle button, the side navigation shrinks, but the main content area maintains the same width. How can I make the main content area fill the full width?

function toggleSidebar() {
    const sidebar = document.querySelector('.sidebar');
    sidebar.classList.toggle('shrink');
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    height: 100vh;
}

.container {
    display: grid;
    grid-template-columns: 200px minmax(0,1fr); /* Sidebar takes 200px, main content takes remaining space */
    height: 100%;
    grid-template-rows: 1fr; /* Only one row for this layout */
}

.sidebar {
    background-color: #333;
    color: white;
    padding: 15px;
    overflow: hidden;
    transition: width 0.3s ease-in-out; /* Transition effect for shrinking */
}

.sidebar ul {
    list-style-type: none;
}

.sidebar ul li {
    margin-bottom: 10px;
}

.sidebar ul li a {
    color: white;
    text-decoration: none;
}

.main-content {
    background-color: red;
    padding: 20px;
    overflow: auto;
}

.sidebar.shrink {
    width: 50px; /* Shrinks the sidebar width to 50px */
}

.sidebar.shrink ul {
    display: none; /* Hide the links when the sidebar is shrunk */
}

.main-content {
    transition: margin-left 0.3s ease-in-out; /* Adjust content area when sidebar shrinks */
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Grid Layout</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
   <button onclick="toggleSidebar()">Toggle Sidebar</button>
    <div class="container">
        <nav class="sidebar">
            <!-- Side Navigation Content -->
            <ul>
                <li><a href="#">Home</a></li>
                <li><a href="#">About</a></li>
                <li><a href="#">Services</a></li>
                <li><a href="#">Contact</a></li>
            </ul>
        </nav>
        <main class="main-content">
            <!-- Main Content Area -->
            <h1>Welcome to the main content area</h1>
            <p>This area should adjust its size based on the sidebar.</p>
        </main>
    </div>
 

</body>
</html>

Share Improve this question asked 2 days ago Velugoti VenkateswarluVelugoti Venkateswarlu 2133 silver badges6 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

You have to modify the grid container, not the container elements, to show/hide the sidebar.

The only CSS property you need to modify is grid-template-columns inside the .container CSS selector:

.container {
  display: grid;
  grid-template-columns: 0 1fr;
}

.container.sidebar-opened {
  grid-template-columns: 200px 1fr;
}

I leave you an example below with a smooth transition:

function toggleSidebar() {
  const container = document.querySelector(".container");
  container.classList.toggle("sidebar-opened");
}
.container {
  display: grid;
  grid-template-columns: 0 1fr;
  transition: grid-template-columns 300ms;
  height: 100svh;
}

.container.sidebar-opened {
  grid-template-columns: 200px 1fr;
}

/* Other non-related styles */
html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 0;
}

aside {
  height: 100%;
  padding: 10px;
  background-color: wheat;
}

main {
  height: 100%;
  padding: 10px;
  background-color: lightblue;
}

button {
  position: fixed;
  top: 10px;
  right: 10px;
}
<div class="container">
  <aside>Sidebar</aside>
  <main>Main content</main>
</div>
<button onclick="toggleSidebar()">Toggle sidebar</button>

You need a new shrink class to make sure it's being injected via JavaScript when you close the sidebar.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Sidebar Layout</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <button class="toggle-button" onclick="toggleSidebar()">Toggle Sidebar</button>
    <div class="container">
        <nav class="sidebar">
            <ul>
                <li><a href="#">Home</a></li>
                <li><a href="#">About</a></li>
                <li><a href="#">Services</a></li>
                <li><a href="#">Contact</a></li>
            </ul>
        </nav>
        <main class="main-content">
            <h1>Welcome to the main content area</h1>
            <p>This area should adjust its size based on the sidebar state.</p>
        </main>
    </div>
    <script src="script.js"></script>
</body>
</html>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    height: 100vh;
}

.toggle-button {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 1000;
    padding: 10px 20px;
    background-color: #333;
    color: white;
    border: none;
    cursor: pointer;
    border-radius: 5px;
    transition: background-color 0.3s ease-in-out;
}

.toggle-button:hover {
    background-color: #555;
}

/* Container Grid Layout */
.container {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr); /* Sidebar width and main content fill */
    height: 100%;
    transition: grid-template-columns 0.3s ease-in-out;
}

/* Sidebar Styling */
.sidebar {
    background-color: #333;
    color: white;
    padding: 15px;
    overflow: hidden;
    transition: transform 0.3s ease-in-out;
}

.sidebar ul {
    list-style-type: none;
}

.sidebar ul li {
    margin-bottom: 10px;
}

.sidebar ul li a {
    color: white;
    text-decoration: none;
}

/* Main Content Styling */
.main-content {
    background-color: red;
    padding: 20px;
    overflow: auto;
}

/* Hidden Sidebar State */
.container.shrink {
    grid-template-columns: 0 minmax(0, 1fr); /* Sidebar is hidden, main content takes full width as 0 column is stated here */
}

.sidebar.shrink {
    transform: translateX(-200px); /* Completely hide sidebar */
}
function toggleSidebar() {
    const container = document.querySelector('.container');
    const sidebar = document.querySelector('.sidebar');

    // Toggle classes to shrink/hide the sidebar
    container.classList.toggle('shrink');
    sidebar.classList.toggle('shrink');
}

While you've already accepted an answer, I wanted to share an alternative that doesn't require JavaScript. It's worth pointing out that while the following answer works in contemporary browsers and is newly-available in Baseline (thanks to Firefox catching up somewhat recently), this is only true for versions:

  • Chrome 85
  • Edge 85
  • Firefox 128
  • Opera 71
  • Safari 16.4

If you have users with older browsers you could either rely on JavaScript, or potentially use a shim for those browsers that this can't work with, or even use an @supports() declaration to progressively enhance your project only for those browsers that can't use @property or, potentially, even the :has() pseudo-class.

With all that said, the possible approach is below with explanatory comments in the code:

/* here we've set up some layers for the CSS in order to establish multiple different rules,
   fundamentally priority increases from left to right (there are caveats around !important
   and so on, but check the references), so the first layer (reset) is least important but
   normalises the layout, the next layer is your posted CSS, and the demo layer is
   where I've written mine: */
@layer reset, from-question, demo;
/* using an @import to bring in the reset from a CDN, and using the layer() function to
   assigne a layer name to the imported stylesheet: */
@import url(https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css) layer(reset);

@layer from-question {
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  body {
    font-family: Arial, sans-serif;
    height: 100vh;
  }

  .container {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    /* Sidebar takes 200px, main content takes remaining space */
    height: 100%;
    grid-template-rows: 1fr;
    /* Only one row for this layout */
  }

  .sidebar {
    background-color: #333;
    color: white;
    padding: 15px;
    overflow: hidden;
    transition: width 0.3s ease-in-out;
    /* Transition effect for shrinking */
  }

  .sidebar ul {
    list-style-type: none;
  }

  .sidebar ul li {
    margin-bottom: 10px;
  }

  .sidebar ul li a {
    color: white;
    text-decoration: none;
  }

  .main-content {
    background-color: red;
    padding: 20px;
    overflow: auto;
  }

  .sidebar.shrink {
    width: 50px;
    /* Shrinks the sidebar width to 50px */
  }

  .sidebar.shrink ul {
    display: none;
    /* Hide the links when the sidebar is shrunk */
  }

  .main-content {
    transition: margin-left 0.3s ease-in-out;
    /* Adjust content area when sidebar shrinks */
  }
}

/* effectively, this is where my answer starts: */
@layer demo {

  /* declaring and initialising a new property, which is accessible as a variable within the
     CSS; we're doing this so that we can use a transition using this property. Each of the
     shown properties are required, though obviously the property-values should be changed
     as appropriate (see the references for a full explanation): */
  @property --sidebarWidth {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
  }

  /* ensuring that the <main> element takes the full space on the block-axis, the axis
     on which blocks are laid out relative to one another; in English, this is vertical
     equivalent to "height," other languages vary: */
  main {
    block-size: 100%;
  }

  /* my naming convention for <label> elements used as switches is to end their id
     with the suffix of "-toggle" to assign a meaningful name, here we select all
     elements with a "for" attribute that ends with ($=) the string "toggle":*/
  [for$="toggle"] {
    border: 1px solid;
    border-radius: 0.3em;
    cursor: pointer;
    display: inline-block;
    margin-block: 0.4em;
    margin-inline: 0.4em;
    padding-block: 0.2em;
    padding-inline: 0.4em;
  }

  /* visually hiding the <input> element: */
  input[type=checkbox][id$=toggle] {
    aspect-ratio: 1;
    block-size: 1px;
    overflow: clip;
    position: absolute;
  }

  .container {
    display: grid;
    /* I prefer to use named grid-columns, here we have:
          all: full-width, spans all columns,
          sidebar: 0px (from the definition (above) of the custom property),
          main-content: 1fr (taking all remaining space)
    */
    grid-template-columns: [all-start sidebar-start] var(--sidebarWidth) [sidebar-end main-content-start] 1fr [main-content-end all-end];
    /* here we specify the transition on the grid-template-columns property, which will take 350 milliseconds, and progress linearly: */
    transition: grid-template-columns 350ms linear;

    /* Using CSS nesting to select, and style, the current element (.container) that has a #sidebar-toggle
       element which is :checked: */
    &:has(#sidebar-toggle:checked) {
      /* here we update the property-value of the --sidebarWidth custom property, this value is then used in the
         grid-template-columns declaration, and the animation starts: */
      --sidebarWidth: 200px;
    }
  }
}
<!-- the <main> element is used to wrap all page content simply to make
     writing the answer - in terms of copy/pasting from the DOM easier
     in the event I use JavaScript to modify HTML, other than that it's
     not necessary: -->
<main>
  <!-- removed this element because this is possible without JavaScript
    <button onclick="toggleSidebar()">Toggle Sidebar</button>
  -->
  <!-- instead of the <button>, I'm using a <label> element, simply because
       it allows us to use a state-change (on an <input> associated with this
       <label> via the identical attribute-value for this element's "for"
       attribute, the <input> element's "id") -->
  <label for="sidebar-toggle">
    <span class="labelText">Toggle sidebar</span>
  </label>
  <div class="container">
    <!-- here's the <input> assocuated with the previous <label>
         which affects the state visibility of the sidebar, if
         the <input> is checked (:checked) the sidebar is shown,
         otherwise it's hidden: -->
    <input type="checkbox" id="sidebar-toggle" />
    <nav class="sidebar">
      <!-- Side Navigation Content -->
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Services</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
    </nav>
    <main class="main-content">
      <!-- Main Content Area -->
      <h1>Welcome to the main content area</h1>
      <p>This area should adjust its size based on the sidebar.</p>
    </main>
  </div>
</main>

JS Fiddle demo.

References:

  • @import.
  • @layer.
  • @property
  • aspect-ratio.
  • background-color.
  • block-size.
  • border.
  • border-radius.
  • box-sizing.
  • color.
  • cursor.
  • display.
  • font-family.
  • grid-template-columns.
  • grid-template-rows.
  • height.
  • layer(), discussed on the same page as previous @layer reference.
  • list-style-type.
  • margin.
  • margin-block.
  • margin-bottom.
  • margin-inline.
  • padding.
  • padding-block.
  • padding-inline.
  • position.
  • text-decoration.
  • transition.
  • url().
  • width.

Bibliography:

  • Baseline.

本文标签: javascriptHow to expand one column width while other column shrinks in css grid layoutStack Overflow