One very common question on CSS is how to vertically center an element. With CSS3 being able to do so many special effect, why they are not including the vertically center function into CSS3?
I don't believe it is a difficult function to add if even a beginner developer can make a function to center things with javascript. And with so many hacks for different situations, it is clear that with CSS alone it is possible to center things vertically. So maybe there are other reasons that they decide not to make it a standard property?
That is because how layout is performed with CSS — CSS is predominantly arranging items on the x-axis, like how 100% width works as expected but not 100% height. This is likely due to the possible "calculation/logic loop" that happens as width is dependent on height and vice versa, so one axis must always be prioritized when it comes to calculation.
Extra info by #BoltClock:
The x-axis thing has to do with the natural flow of text in a
document. Remember that the Web started off as a series of pages, so
HTML and CSS were originally built around this fundamental premise -
it has since evolved into an application platform, but the legacy is
still there. Flexbox is the CSS3 way to vertically center boxes - the
only issue is cross-browser support, but since the question is about
CSS3 anyway, that's to be expected.
Similarly, in terms of dictating alignment, horizontal alignment is easy because the width of an element is often implicitly or explicitly stated, like how a block element automatically has a implicit width of 100% unless otherwise stated, allowing for easy calculation of a center position along the horizontal axis.
However, this does not work for the case of vertical alignment, where often than not the vertical dimension is dependent on the amount, length and size of the content. In the case where vertical height is explicitly stated, this can actually be easily done:
by using the CSS flexbox method
The good: standards compliant and very simple, dimension of element of interest does not have to be fixed
The bad: lack of extensive cross-browser support, but appears very promising today
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and CSS transforms
The good: extensive cross-browser support, dimension of element of interest does not have to be fixed
The bad: fuzzy text rendering (occasionally) due to sub-pixel translation
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relatve;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and negative margins
The good: extremely straightforward
The bad: dimension of element of interest MUST be fixed
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relative;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
width: 200px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -100px;
}
<div class="box">
<div class="content">I am centered</div>
</div>
Related
I have been tasked with styling a banner, however the banner itself is a third party tool with severely limited styling options. It's probably easier if I share an example of what I'm working with and then talk through the limitations and what I'm trying to achieve.
body {
margin: 0;
}
.main {
height: 200vh;
min-height: 250px;
width: 1200px;
background: #cdcdcd;
margin: 0 auto;
padding: 20px;
}
<div class="main">
Main website content
</div>
<div class="banner" style="position: fixed; width: 100%; max-width: 600px; height: 80px; background: gray; bottom: 20px; right: 20px; color: white; padding: 20px;">Banner content</div>
Here is a version in Codepen if that's easier.
As you can see, the main website content is centered and is responsive up to (in this case) 1200px, after which the width becomes fixed. The banner needs to always sit at the bottom right, but it should remain within the constraints of the main website content. When the viewport is less than 1200px this solution works fine, the issue I have is of course that on viewports wider than 1200px, the banner breaks out of the constraints of the site.
Generally this wouldn't be an issue, it's easily fixed with calc() and a media query to get the viewport width, but now come the limitations of the banner tool:
I can only add inline CSS via the tool to the element banner, there is no wrapper or inner element I can target
I cannot add CSS to the site that the banner will appear on
I cannot use JavaScript, either on the site or in the banner tool
I can't affect the HTML mark-up in any way (e.g. I can't put the banner inside main
Sorry for the long introduction but hopefully that explains my dilemma. My question is this: is it possible, using CSS calc(), to determine when my viewport is above 1200px and to add (half) that amount to my right offset without affecting the offset when the viewport is less than 1200px, or is there just no solution to this?
Here is one idea that rely on the use if min() in order to define the max-width. You make it either 600px (for bigger screen) or 50% (for small screen) and then adjust the position using translate after centring the element:
body {
margin: 0;
}
.main {
height: 200vh;
min-height: 250px;
width: 1200px;
background: #cdcdcd;
margin: 0 auto;
padding: 20px;
}
* {
box-sizing:border-box;
}
<div class="main">
Main website content
</div>
<div class="banner" style="position: fixed; width: 100%; max-width: min(50%,600px); height: 100px; background: gray; bottom: 20px; right: 0;left:0;margin:auto;transform:translate(50%);border:1px solid red; color: white; padding: 20px;">Banner content</div>
The support is still not good (https://caniuse.com/#feat=mdn-css_types_min) but shortly it will be available on Firefox and all the major browser will be covered.
This is yet another question about centering vertically in a div, but I've tried lots of the solutions discussed in other answers to no avail.
Here's an example of the code to play with: https://codesandbox.io/s/z2qzxwk99x
The arrow-icon is centering vertically in the viewport, instead of the viewer-wrapper div. As such, it drops off of the image completely, instead of staying centered vertically, if you make the page very narrow.
.viewer-wrapper {
background-color: #1b8dbb;
position: relative;
}
.arrow-wrap {
position: absolute;
max-height: 100%;
line-height: 95vh;
background-color: #4cae4c;
margin: auto;
opacity: .9;
left: 0px
}
.arrow-icon {
background-color: orangered;
}
.comic-page {
object-fit: contain;
max-height: 95vh;
width: 100%;
}
<div className="viewer-wrapper">
<div className="arrow-wrap">
<LeftArrow className="arrow-icon" size={75} />
</div>
<img className="comic-page"
src="http://assets-production.rovio.com/s3fs-public/hatchlings_0.jpg"
about="This is an image"
/>
</div>
The magic here is Flexbox (and Grids, but Flexbox has way better browser support). Keeping the same HTML layout, you could use somerthig like:
.viewer-wrapper {
background-color: #1b8dbb;
display: flex;
align-items: flex-start;
}
.arrow-wrap {
background-color: #4cae4c;
margin: auto;
opacity: .9;
}
.arrow-icon {
background-color: orangered;
}
.comic-page {
object-fit:contain;
min-height: 100%;
max-width: 100%;
}
Depending on how much support you need of IE, there are different ways to accomplish vertical alignment.
If you don't have any need to support IE, you could use the flex display property:
.viewer-wrapper{
display: flex;
align-items: center;
}
or, continue with what it looks like you're trying to do. What your missing to do so is the top: property. Since you've already correctly made the parent element position: relative, setting top: 50% will set your arrow to begin halfway down the viewer-wrapper element. From here you need to set a negative margin to correct for the arrow's height. Since it looks like you specify a size of 75(px?), you can achieve this like:
.arrow-wrap {
position: absolute;
background-color: #4cae4c;
margin-top: -37.5px;
left: 0px;
}
You shouldn't have to set any other margins.
A great resource for this, and what I used to help answer you, is howtocenterincss.com.
I need to centralize a block made by a div, for instance, in the middle of the screen of a fluid grid layout. Inside this block, I want to put an image, a password field and a submit button. When I do this in a non-responsive layout with the following code, it works perfect but, in a fluid grid layout it doesn't:
#block-login {
width: 650px;
height: 378px;
float: left;
clear: both;
margin-top: -189px;
margin-left: -325px;
position: absolute;
top: 50%;
left: 50%;
text-align: center;
}
the fluid div I refer is one like this:
<div class="gridContainer clearfix">
<div id="div1" class="fluid"></div>
</div>
thanks in advance.
There are a few methods of doing so: CSS tables, CSS transforms and CSS flexbox. I typically avoid using CSS tables, though. Both CSS transforms and flexbox solutions, unlike the fixed negative margin solution, is that they are child-dimension agnostic (size of child does not matter, fixed or fluid).
For CSS transforms, a major caveat is that the parent's dimensions (that of .gridContainer) has to be explicitly predefined. The trick is to position it's child absolutely, but offset by 50% to the left and from the top. In order to take into account the child's own computed dimensions, we use CSS transforms to fix that. You might want to add vendor prefixes to the transform property though.
.gridContainer {
position: relative;
width: (have to declare);
height: (have to declare);
}
.gridContainer > div {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
The other solution (which I feel is way more elegant, but lacks cross-browser support in older browsers) is to use CSS flexbox:
.gridContainer {
display: flex;
align-items: center;
justify-content: center;
}
You can view the demo of both solutions here: http://jsfiddle.net/teddyrised/B7PVh/
This is a possible solution for you :
FIDDLE
CSS :
body,html,.gridContainer{
width:100%;
height:100%;
margin:0;
position:relative;
}
#div1 {
width: 80%;
height: 80%;
margin:0;
position: absolute;
top: 10%;
left: 10%;
text-align: center;
background:gold;
}
If you don't need to support IE9 and below, you can get a fixed-wdith, fixed-height div centered in a fluid container by using relative positoining and the new CSS calc() function:
<div class="gridContainer">
<div id="#block-login">
</div>
</div>
#block-login {
position:relative;
top:calc(50% - 189px); /* 50% - 1/2 of it's own height */
left:calc(50% - 325px); /* 50% - 1/2 of it's own width */
}
A jsfiddle demo
Note: caniuse.com lists "partial support" for calc() with ie-9
I am using transform: skew to create the effect of a down arrow on my banner image using both the :before and :after tags. The result should look like the following:
However, in IE 9-11 there seems to be a rounding issue. At some heights there is one pixel from the background image that shows below the skewed blocks resulting in the following:
In my case, the banner is a percentage of the total height of the window. Here is the some sample code which should be able to reproduce the problem:
HTML
<div id="main">
<div id="banner"></div>
<section>
<h1>...</h1>
<p>...</p>
</section>
</div>
CSS
#banner {
position: relative;
background-color: green;
width: 100%;
height: 75%;
overflow: hidden;
}
#banner:before,
#banner:after {
content: '';
display: block;
position: absolute;
bottom: 0;
width: 50%;
height: 1.5em;
background-color: #FFFFF9;
transform: skew(45deg);
transform-origin: right bottom;
}
#banner:after {
right: 0;
transform: skew(-45deg);
transform-origin: left bottom;
}
body {
background-color: #333;
position: absolute;
width: 100%;
height: 100%;
}
#main {
max-width: 40em;
margin: 0 auto;
background-color: #FFFFF9;
position: relative;
height: 100%;
}
section {
padding: 0 1em 5em;
background-color: #FFFFF9;
}
And here a working example.
Yes, seems to be a rounding issue – and I don’t know of anything that one could do to fix this. It’s in the nature of percentage values that they don’t always result in full pixel values – and how rounding is done in those cases is up to the browser vendor, I’m afraid.
I can only offer you a possible workaround (resp. “cover up”) that seems to work – if the layout really is as simple as this, and the main content area has a white background, and no transparency or background-image gets involved there.
Pull the section “up” over the banner by a negative margin of -1px (eliminated top margin of h1 here as well, otherwise it adjoins with the top margin of the section – countered by a padding-top), so that its background simply covers up that little glitch:
section {
padding: 1em 1em 5em;
background-color: #FFFFF9;
position:relative;
margin-top:-1px;
}
section h1:first-child { margin-top:0; }
Well, if you look closely, that makes the corner of triangle look slightly “cut off” (by one pixel) in those situations where the rounding glitch occurs – if you can live with that (and your desired layout allows for it), then take it :-) (And maybe serve it to IE only by some means). If not – then sorry, can’t help you there.
As the title says, I need two divs to be equally high. They should be as high as it needs to be for the content to fit. The current CSS is:
.portfolioleft{
float:left;
width:189px;
background-color: #436FAC;
min-height: 100px;
height: auto;
color: #FFF;
padding: 20px;
margin-bottom: 20px;
border-radius: 10px;
}
.portfolioleft img{
border-radius: 10px;
}
.portfolioright{
float:right;
width:500px;
background-color: #436FAC;
min-height: 100px;
height: auto;
color: #FFF;
padding: 20px;
margin-bottom: 20px;
border-radius: 10px;
}
.portfolioright a{
color:#FFFFFF;
}
and the html for the divs is:
<div class="portfolioleft"><img src="img" alt="img" width="189" height="311" /></div>
<div class="portfolioright">
<h2>Title</h2>
<p>Text</p>
</div>
<div class="clear"> </div>
CSS alone cannot tackle this feat (unless you want a hack solution where you can use an image). You will need to implement a JS solution. Since the content is dynamic and you do not know how high the columns will be, you will need to access the DOM to determine the height of the tallest column then apply to the indicated columns. I use the following regularly and it works quite well and is easy to implement.
http://www.jainaewen.com/files/javascript/jquery/equal-height-columns.html
Unfortunately this is a tricky problem in CSS. If you only want to extend the background color of your left sidebar to the bottom of the section (with its height defined by the right div), try wrapping them inside a parent div (which scales to the height of the right div), then positioning the left div with position:absolute and height of 100% like so:
<div class="portfolio">
<div class="portfolioleft">...</div>
<div class="portfolioright">...</div>
</div>
.portfolio {
position: relative;
background: white;
}
.portfolio .portfolioleft {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 100%;
background: #436FAC;
}
.portfolio .portfolioright {
margin-left: 200px;
}
If BOTH sides are dynamic and you need both heights to match, the only surefire way to make it work across all major browsers is to resort to a table-based layout with two columns, as karmically bad as that might be.
cell properties in your left right div
i checked your code and replace the float into display table-cell
you can check to this live http://jsfiddle.net/rohitazad/prMLh/1/