Responsive 2-column CSS layout including sidebar w

2019-03-16 17:42发布

问题:

Cannot find a solution for this (what I'm guessing must be a pretty common problem) anywhere.

I am creating a responsive design with a sidebar, where the sidebar needs to have a fixed width of 200px and has unknown height. How can I make it so the main content area takes up all the remaining width, without anything misbehaving.

The closest I've come to it is the following, but the problem with it is that the sidebar can overlap the footer. Can anyone suggest a fix for my code, or share with me some code that works?

            * {
            padding: 0;
            margin: 0;
            outline: 0;
            -moz-box-sizing: content-box;
            -webkit-box-sizing: content-box;
            box-sizing: content-box;
        }
        body {
            background: orange;
        }
        #container {
            max-width: 1000px;
            min-width: 768px;
            margin: 0 auto;
            background: yellow;
            position: relative;
            height: 100%;
        }
        #header {
            background: purple;
            color: white;
            text-align: center;
            padding: 10px;
        }
        #main {
            position: relative;
        }
        aside {
            background: blue;
            width: 200px;
            color: white;

            position: absolute;
            top: 0;

            /* change this to "right: 0;" if you want the aside on the right. Also, change the "margin-left" code, below. */
            left: 0;

            padding-top: 20px;
            padding-bottom: 20px;

            padding-left: 10px; /* If you change this value, remember to change the margin-left value of #primary */
            padding-right: 10px; /* ditto */
        }
        #primary {
            background: red;

            /* change this to margin-right if you want the aside on the right. Also change the "left" code, above. */
            margin-left: 220px; /* aside_width + aside_left_padding + aside_right_padding = 200px + 10px + 10px */
            padding: 1em; /* whatever */
        }
        #footer {
            background: green;
            color: white;
            padding: 10px;
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
        }

        <div id="container">
        <div id="header">
            <h1>LAYOUT TEST #2</h1>
        </div>
        <div id="main">
            <div id="primary">
                <h2>THIS IS THE MAIN CONTENT ** THIS IS THE MAIN CONTENT ** THIS IS THE MAIN CONTENT</h2>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <h2>sub heading</h2>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <h2>sub heading</h2>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
            </div>
            <aside>
                <h3>navigation (left)</h3>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
                <p>lorem ipsum</p>
            </aside>
        </div>
        <div id="footer">
            <h1>LAYOUT TEST #2</h1>
        </div>
    </div>

回答1:

I think the approach with all those position: absolute is not the best one.

  1. You want to have a container element with a max-width and margin: 0 auto. Not sure why you might want a min-width as well; you can of course.

  2. Any block element that you put automatically takes all the width of the parent element. Hence, there's no problem with the header and footer, just position them in the right spot and they will render properly.

  3. As you correctly did, use a container element for your main section. Since the elements are rendered left to right, you might want to write the aside before the #primary.

  4. Apply float: left to the aside with your desired fixed-width.

  5. The main content #primary element will take the remaining space automatically (or just apply width: auto. Note: the remaining space is the remaining space of the parent element, so, if you set the min-width on the parent element, don't expect your #primary to be narrower!

  6. Now you will have a problem: the container element #main will not get the proper height. That's because of an issue with float. To force a parent element to get to the height of its floated children, use overflow: hidden.

You should be ready to go. Here is a slightly modified version of your code.



回答2:

1 = With flexbox: http://jsfiddle.net/rudiedirkx/CjWbv/2/

#main {
    display: flex;
}
#primary {
    background: #bbb;
    flex: 1;
}
aside {
    background: #ddd;
    flex: 0 0 200px;
}

2 = with calc(): http://jsfiddle.net/rudiedirkx/CjWbv/

#main:after { clearfix here }
#primary {
    float: left;
    background: #bbb;
    width: calc(100% - 200px);
}
aside {
    background: #ddd;
    float: right;
    width: 200px;
}

Both will require a fallback for older browsers (and vendor prefixing). Take your pick from the other answers.



回答3:

Until we get flexbox, I believe the best way to do what you are looking for is to simply use the css display: table;. You will need to set the container to display: table;, and then each of the columns, just set to display: table-cell;. This will eliminate the need for using floats or any other JS magic. Also, this works back to IE8. I know it feels sketchy using anything with the word "table" for layout, but just give it a try.

Check out this link for more info.

Here is an updated version of your code.

EDIT: example code

html: Assuming this markup

<div id="main">
    <div id="sidebar"></div>
    <div id="content"></div>
</div>

css:

#main {
    display: table;
    width: 100%;
}
#sidebar {
    display: table-cell;
    width: 200px;
}
#content {
    display: table-cell;
    /* no need to specify width. 
     * width will auto fill remaining width of parent `table` #main.
     * so 100% - 200px */
}


回答4:

#main { position: relative; overflow:hidden;}

This stops the sidebar misbehaving.



回答5:

You can fix it with adding margin-bottom: FOOTER_HEIGHT to the aside or use the following method instead:

<div id="container">
    <div id="header">
        YOUR_HEADER
    </div>
    <div id="body>
        <div id="sidebar">
            YOUR_SIDE_BAR_CONTENT
        </div>
        <div id="main">
            YOUR_CONTENT
        </div>
        <br />
    </div>
    <div id="footer">
        YOUR_FOOTER
    </div>
</div>

And the CSS:

#sidebar {
    width: ...;
    height: ...;
    float: right;
}
#main {
    margin-right: WIDTH_OF_SIDE_BAR;
}
#body > br {
    clear: both;
}