sdbbs
sdbbs

Reputation: 5478

Responsive design with divs in each page corner

I'm working on a responsive design, where I have an ID div on top, and in the rest of the page, I should have div buttons in each of the corners of the page (i.e., I should have 2x2 divs, two divs side-by-side on each row, first row aligned to top of page, second row to bottom of page) -- when in landscape view. (Something similar was discussed in Placing 4 html elements in every corner of a div, but I cannot find out how to apply that solution to my example here).

When in portrait view, the buttons' width should be about the size of the viewport width, and they should be below one another. I came up with the following example:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <script type="text/javascript">
  </script>
  <style type="text/css">
html, body {
  margin: 0;
  padding: 0;
}
.testbtnholder {
  border: 2px solid gray;
  width: calc(100% - 1em);
  height: calc(100% - 2em);
  position: relative;
  margin-top: 0px;
  margin-left: 1em;
  margin-right: 1em;
  margin-bottom: 1em;
}
.testbtn {
  border: 2px solid #FF9999;
  width: calc(50% - 1em);
  height: 5em;
  /* line-height: 5em; // does vertical align to middle, but only for single-line text; http://phrogz.net/css/vertical-align */
  position: absolute;
  text-align: center;
  /* top: 50%; margin-top: -2.5em; // should do vertical align to middle, but it doesn't */
}
@media all and (orientation:landscape) {
  .testbtn:nth-child(even) {
    right: 0;
  }
  /*nth-last-child(-n+2) - select 2 last items from the parent*/
  .testbtn:nth-last-child(-n+2) {
    bottom: 0;
  }
}
@media all and (orientation:portrait) {
  .testbtn {
    position: relative;
    width: calc(100%);
  }
}
#dreport {
  font-size: 0.76em;
}
  </style>
</head>

<body>
  <div id="dreport">Test text</div>
  <div class="testbtnholder">
    <div class="testbtn">Test <br/> one</div>
    <div class="testbtn">Test two</div>
    <div class="testbtn">Test three</div>
    <div class="testbtn">Test <br/> four</div>
  </div>
</body>
</html>

This example in landscape somewhat works in Chromium 48, but fails in Firefox 50 (below, left image is Chromium, right image is Firefox):

chromium-ff-problem

(In fact, if I add <!DOCTYPE html> at start of the HTML, also Chromium produces the same bad layout as FF!)

My problems/questions are:

Otherwise, in portrait mode, the layout generally works (apart from the margin problem):

ff-chrome-portrait

Upvotes: 0

Views: 222

Answers (3)

michaPau
michaPau

Reputation: 1650

Personally I would use absolute position for the landscape mode and switch to flexbox column layout for portrait mode... seems neater for me.

example:

* {
      /*
      to avaid srollbars when using borders set box-sizing
      here it is set to every element
      */
      box-sizing: border-box;
    }

    html, body {
      margin: 0px;
      padding: 0px;
      height: 100%;
    }

    body {
      display: flex;
      flex-direction: column;
    }
    #header-contaier {

      height: 2em;


    }
    #button-container {
      position: relative;
      flex: 1 0 auto;
      margin-top: 0.5em;

    }

    .div-button {
      /*the width in landscape mode - default here*/
      width: calc(50% - 1em);
      height: 5em;
      text-align: center;
      vertical-align: middle;
      line-height: 5em;
      margin: 0;
      background: rgba(0, 75, 153, 0.8);
    }
    @media all and (orientation:landscape) {

      #button-1 {
        position: absolute;
        top: 0px;
        left: 0px;
      }
      #button-2 {
        position: absolute;
        top: 0px;
        right: 0px;
      }
      #button-3 {
        position: absolute;
        bottom: 0px;
        left: 0px;
      }
      #button-4 {
        position: absolute;
        bottom: 0px;
        right: 0px;
      }
    }
    @media all and (orientation:portrait) {
      /*switch to flexbox column layout*/
      #button-container {
        display: flex;
        flex-direction: column;

      }
      .div-button {
        /*set width to 100% and give it some margin-bottom*/
        flex: 0 0 5em;
        width: 100%;
        margin-bottom: 0.5em;
      }
    }
<div id="header-container">Header container</div>
  <div id="button-container">
    <div id="button-1" class="div-button">Button 1</div>
    <div id="button-2" class="div-button">Button 2</div>
    <div id="button-3" class="div-button">Button 3</div>
    <div id="button-4" class="div-button">Button 4</div>
  </div>

Surly there are more possibilities for this layout - it's just an example. (Run the snippet in Full Page on SO to see the switch between landscape and portrait)

You've got scrollbars because when using borders you should use box-sizing: border-box; that the border width is not calculated in the size.

For vertical-align to work you have to set the line-height corresponding. (see the css in this example)

Other techniques to center text are possible: For example this question on SO

Upvotes: 1

Saurav Rastogi
Saurav Rastogi

Reputation: 9731

I've tried using Flexbox here, please have a look at the snippet below:

html, body {
  margin: 0;
  padding: 0;
}
.testbtnholder {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border: 2px solid gray;
  height: calc(100vh - 2em);
  position: relative;
  margin-top: 0px;
  margin-left: 1em;
  margin-right: 1em;
  margin-bottom: 1em;
}
.row {
  display: flex;
}
.row .testbtn:last-child {
  margin-left: auto;
}
/* .row:last-child .testbtn {
  align-self: flex-end;
} */
.testbtn {
  border: 2px solid #FF9999;
  padding: 10px;
  width: 40%;
  height: 5em;
  height: auto;
}
@media all and (orientation:landscape) {
  .testbtn:nth-child(even) {
    right: 0;
  }
  /*nth-last-child(-n+2) - select 2 last items from the parent*/
  .testbtn:nth-last-child(-n+2) {
    bottom: 0;
  }
}
@media all and (orientation:portrait) {
  .row {
    flex-direction: column;
  }
  .row .testbtn:last-child {
    margin-left: 0;
  }
  .row:last-child .testbtn {
    align-self: stretch;
  }
  .testbtn {
    position: relative;
    flex: 1;
    align-self: stretch;
    width: auto;
  }
}
#dreport {
  font-size: 0.76em;
}
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <script type="text/javascript">
  </script>
</head>

<body>
  <div id="dreport">Test text</div>
  <div class="testbtnholder">
    <div class="row">
      <div class="testbtn">Test <br/> one</div>
      <div class="testbtn">Test two</div>
    </div>
    <div class="row">
      <div class="testbtn">Test three</div>
      <div class="testbtn">Test <br/> four</div>
    </div>
  </div>
</body>
</html>

Hope this is what you are trying to achieve.

Upvotes: 1

Martin
Martin

Reputation: 22770

  • You should always add <!DOCTYPE html>. This should not be an exception

I don't quite understand exactly why you're working this way, but from using your code as provided and making the following change:

.testbtnholder {
    /* position: relative; */
}

(in landscape orientation)

This completely solved the layout issue for me.

Also, you have a secondary issue with width being slightly offsize from the window size, I think you need to tweak your width calc .


Questions:

Even if I'm resetting margin/padding to 0 for html and body, and then explicitly setting margin-left and margin-right for .testbtnholder, in both FF and Chromium I get some sort of a left margin which "pushes" the rest of the layout, and so scrollbars appear. How can I set the margins explicitly, so I don't have to rely on overflow:hidden; to hide scrollbars (and so the borders of .testbtnholder appear horizontally centered in the page)?

Use margin:auto to auto centre a set-width container. Such as:

div {
    display:block;
    width: 80%;
    min-width: 200px;
    max-width: 800px;
    margin:auto; /* will always be horizontally centered */
}

I'd like the text in the div buttons to be centered both horizontally and vertically; I have already achieved horizontal centering with text-align: center, but cannot get vertical centering (with vertical-align: middle) to work

This is fairly straight forward with Flex Box.

How can I get Firefox to render the same image as Chromium

Once you have a consistent CSS structure set up, Firefox and Chromium are pretty consistent. Safari and IE will probably cause you more inconsistency problems.

Is there a better layout approach than the one I've taken here?

Yes, try using Flex Box.

Edit: I see you've already referenced reading up on Flex Box, to be honest, the link to the CSS tricks Flexbox page is a pretty good starting point, as it goes through each aspect of flexbox point by point. Stick at it and you'll come through wiser and more powerful :)

Upvotes: 2

Related Questions