hugo der hungrige
hugo der hungrige

Reputation: 12912

How to always center a flexible square in viewport with pure CSS?

I know this question: Height equal to dynamic width (CSS fluid layout)

But I want more!! I want a flexible container which has always the aspect ratio of a square but with max-height and max-width of 100% of the page (the window element) and on the top of it is always vertically and horizontally centered.

Like this:

// Container matches height of the window
// container-height = 100%; container-width = absolute-container-height
-page/browser-window-
-      #######      -
-      #cont-#      -
-      #ainer#      -
-      #######      -
---------------------


// container matches width of the window
// container-width = 100%;  container-height = absolute-container-width
--page---
-       -
-       -
-#######-
-#######-
-#######-
-#######-
-       -
-       -
---------

Is it possible to achieve this with pure css (and even better cross-browser)?

Edit: I know there is calc() for css3, but due to the poor mobile browser-support, I don't want to use it.

Edit2: Seems like, I didn't make myself clear enough. I need height and width of the wrapper to match the height OR the width of the window, depending on which is smaller.The square-container should never exceed the smaller value of the window-height/width.

This is, how it would be done with jQuery:

 // container/#main-wrapper has top: 50%,  left: 50%, position: absolute  via css  
 $(window).resize(function () {
    var $ww = $(window).width();
    var $wh = $(window).height();

    if ($ww > $wh) {
        $('#main-wrapper').css({
            height: $wh,
            width: $wh,
            marginTop : ($wh / 2) * -1,
            marginLeft : ($wh / 2) * -1
        });
    } else {
        $('#main-wrapper').css({
            height: $ww,
            width: $ww,
            marginTop : ($ww / 2) * -1,
            marginLeft : ($ww / 2) * -1

        });
    }
});

Upvotes: 6

Views: 2393

Answers (4)

hugo der hungrige
hugo der hungrige

Reputation: 12912

I finally figured it out. The magic ingredients are the view-port units.

Given this html structure:

.l-table
  .l-table-cell
    .square

You can use this css (well actuall its scss, but you get the idea) to make it work

html,
body{
  height: 100%
}
l-table{
  background: orange;
  display: table;
  height: 100%; 
  width: 100%;
}
.l-table-cell{
  display: table-cell;
  vertical-align: middle;
  border: 2px solid black;
}
.square{
  background: red;
  margin: auto;
  @media (orientation:landscape) {
    width: 70vh;
    height: 70vh;
  }
  @media screen and (orientation:portrait) {
    width: 70vw;
    height: 70vw;
  }
}

http://codepen.io/johannesjo/pen/rvFxJ

For those who need it, there is a polyfill.

Upvotes: 4

suryanaga
suryanaga

Reputation: 4012

EDIT: Since writing the below, I appealed on Twitter and got a response from Brian Johnson. He came up with a solution that isn't 100% perfect semantically, but it's pretty damn good and I'll certainly be using it. He asked that I share it in this discussion. LINK

I'm having the same issue right now and I was just typing out pretty much this exact question, so although I can't answer it, I wanted to share what I've found so far in case it helps anyone come up with the final solution.

To clarify, I need my content to fit into a square which fills 60% of the browser's width if portrait or 60% of the height if landscape.

However, this square must never exceed the width or height of the viewport.

Using the technique found here I've managed to create the fluid square, but it still exceeds the viewport when landscape.

width: 60%;
height:0;
padding-bottom: 60%;

Link to Codepen example

I have tried flipping that technique on it's side for landscape but that doesn't work. (You can see that code in the above example, noted out.)

I can't use a simple max-height property because the height is being worked out by the padding-bottom property.

I've thought about adding an extra div as someone else has suggested (C-Link's post is really interesting) but I can't work out how I'd get it to do what we want it do here.

Upvotes: 1

Daniel
Daniel

Reputation: 4946

How about if you take the earlier concept a step further with a similar div as a container. The container has an added max-height & width. I tried this and the container does not throw a scrollbar at me. It is quite interesting in behavior I must say myself. Does this work for you?

<div id="container">
    <div id="centered">A DIV</div>
</div>

    #container {
    top:0;
    bottom:0;
    right:0;
    left:0;
    margin:auto;
    position:absolute;
    width:200px;
    height:200px;
    max-width:100%;
    max-height:100%;
    background:#00f;
    padding:0;
}
#centered {
    background: green;
    bottom: 0;
    height: 80px;
    left: 0;
    margin: auto;
    position: absolute;
    top: 0;
    right: 0;
    width: 80px;
}

updated fiddle: http://jsfiddle.net/djwave28/mBBJM/96/

Upvotes: 0

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

html

<div id="outer">
<div id="inner">YOUR CONTENTS HERE
</div>
</div>

css

html, body{
height: 100%;
}
#outer{
max-height: 100%;
max-width: 100%; 
position: relative; 
height: 100%;
}
#inner{
position: relative; 
top: 50%; 
margin-top: -50% auto auto auto; 
background: red; 
text-align: center; 
color: yellow;
}

See this fiddle.

Upvotes: 0

Related Questions