Centering elements vertically within a block - css

I'm currently redesigning my website from a table layout to CSS. I'm having some problems with what seemed like a very simple task.
The site is simple. A box in the middle of the screen that contains several links.
The old site used <td valign="center"> to center all the links in the box. CSS seems to have no equivalent. I've been centering elements using negative margins like so:
div {
height: 200px;
position: absolute;
top: 50%;
margin-top: -100px;
}
This works fine when you know exactly how big the element you're centering is, but I need to be able to center the links without knowing how much vertical size the links take up. I just want the aligning in the box to act like text-align: center. Only vertically too.
Current website designed with tables
Current progress on the CSS version

You have 4, possibly 5 solutions one added to the bottom since it's a combination of different css from your original and js to set height:
Use a table cell and center it's content vertically
Use display: table-cell; vertical-align: middle; as css for your div
Update margin-top every time the div's height changes via javascript
Use css3 flexbox (you need to use vendor-specific extensions so it won't work on some older browsers)
Simple example using old-style flexbox - chrome version - add a wrapper div and set it's styling to this:
#wrapper { display: -webkit-box; -webkit-box-align: center; }
#wrapper > div { margin: auto; }
fiddle for this http://jsfiddle.net/gK7YU/
New style flexbox - also chrome version, you'll have to add the other vendor prefixes as well as the version without any prefixes in the final product.
#wrapper { display: -webkit-flex; }
#wrapper > div { margin: auto; }
fiddle for this: http://jsfiddle.net/LeHRD/
The fiddles contain a few more css properties so you can see what is happening easily.
Oh, sorry, you don't need the wrapper div, you can just center vertically any content with flexbox... well, anyway the solution I proposed can be combined with display: table-cell; so it works in older browsers as well.
You can also use absolute positioning with specified height jsfiddle.net/N28AU/1
#wrapper { possition:relative }
#wrapper > div { position:absolute;top:0;right:0;bottom:0;left:0;margin: auto;}
you can calculate height from the contained elements and update it via js if you want to avoid negative margins.

I've been to your website and copied the html here.
You can do this:
<style>
#box{
display: table;
}
#box > div {
display: table-cell;
vertical-align: middle;
}
</style>
<!-- Your html part -->
<div id="box">
<div>
Link A
Link B
Link C
Link D
</div>
</div>
You must wrapped a div element inside #box because display: table-cell property won't work properly if you don't have a wrapper element that is set to display: table.
Your example here: jsfiddle

Related

Wrapping a link around an image destroys flexbox layout and causes browser rendering quirks

Struggling to find the right title that isn't just a mixture of "help" and "what, CSS, why?!" so hopefully a couple of you geniuses will find this...!
I have two columns. Each of them has a full-width div inside it which contains a logo. The images are quite different shapes, one being a square and one being a more panoramic aspect ratio. To achieve a balanced look, the images are set to a max-width of 50% and a max-height of 100%. Flexbox is used to center the images both horizontally and vertically.
They look perfectly fine.
// working before wrapping images with links
section.working {
div.flex {
display: flex;
justify-content: center;
align-items: center;
img {
max-width: 50%;
max-height: 100%;
}
}
}
And then I needed to add links.
https://codepen.io/lenoz/pen/VwZyeOG
This is the problem reduced to its most simple, in that the bottom row was the original code I was using to get the perfect layout, and the top row shows what happens when the images were wrapped in tags to make them links. Some points of note:
colours added just to help distinguish boundaries a little - useful for detecting when the link (red background) is no longer constricted to the size of the image inside it (as it ideally should be)
the two columns are separate in the code and not part of a shared container - i.e. one cannot inform the height of the other (want to fix this with CSS not JS)
I should mention that of course there was no way adding links would just work - the <a> tags come in between the flex container and the flex item, so obviously they will mess with the layout.
Much appreciated if you can help me find a CSS solution.
Still here? Read on if you want some more info on my attempts to fix, with a side portion of Chrome weirdness.
It should also go without saying I've spent ages fiddling with this, so here's another link showing some of my efforts that have gotten close: https://codepen.io/lenoz/pen/pozpjVq
The top row (section.help) is my latest attempt, but is a bit of a mess simply because I stopped half way, having suffered frustration sufficient to lead to me making this post.
The middle row, which I'm calling section.weirdness, actually seemed to be a solution for a hot minute. If you're using Chrome, like I am, when you look at the Codepen link you may see nothing on these blue blocks?
But try removing the display: flex attribute from div.flex and, if your Chrome is like my Chrome, you'll see this:
Now, add that same display: flex attribute back on the same div.flex selector and you'll see that suddenly the blue blocks are not blank:
How strange is that? Browser rendering bug or what?
Now find the max-width or max-height attributes on div.image, toggle one of those off and then on again and you'll see that everything suddenly looks right again:
Somehow, without changing any CSS other than toggling it, we've gone from no links showing up at all, to them showing up and looking perfect. You can see how I'd managed to confuse myself into thinking I had got it working!
Just add style="display: contents" to your anchors
"display: contents" causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself
<div>
<a style="display: contents" href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
Here's a simple solution:
I've changed the columns to be flex contexts but retained an inner div to serve as the 50% width constraint. When the imgs are allowed to set their own height explicitly all the other constraints around them flow into place without much fuss, and because the anchors don't have any layout rules, they manage to avoid having any clickable areas outside their image.
With the same max-height on the images, they'll match in the same way as your .working class as long as their containers are the same width.
section {
width: 800px;
display: flex;
}
.column {
background-color: blue;
margin: 5px;
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.column > div {
max-width: 50%;
}
img {
display: block; /* get rid of bottom gap */
max-width: 100%;
max-height: 80px;
}
<section>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/500x500.png" />
</a>
</div>
</div>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
</div>
</section>
Try adding this to your Codepen example:
.flex > a {
flex: 0 0 50%;
height: 100%;
display: flex;
}
div.flex a > img {
max-width: 100% !important;
max-height: 100% !important;
margin: auto;
}
Any immediate child of a container with display: flex is flex item. To prevent that item from growing or shrinking we must set flex-grow and flex-shrink properties to 0. In my case I used flex: 0 0 50% shorthand for that. That last value of 50% is from your initial image max-width property. That + height:100% will make sure that <a> behaves like images in your original example.
Now the fun part: use display: flex again on <a> to make the image flex item again. Since <a> is already properly sized we can set max-width and max-height to `00% to fill available space.
Using margin: auto is a neat trick to center both horizontally and vertically flex child inside of flex container (works only when there is one child).
sidenote: I used important to override specificity without changing markup but I would advise against it and put new CSS class on both a and img.
UPDATE
working fork (Chrome only): https://codepen.io/teodragovic/pen/wvwpWbx?editors=1100
section.broken {
.flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
a {
max-width: 50%;
max-height: 100%;
}
img {
max-width: 100%;
max-height: 100%;
display: block;
}
}

CSS: Image Centering [issue]

http://alexandermasters.com/flora/2015/10/05/corey-boyce/
Trying to horizontally center the image within its respective container.
Can't seem to isolate the correct element with which to apply
display: block;
margin-left: auto;
margin-right: auto;
Have progressively worked my way through the code starting from the image and moving up to no avail.
Try this CSS code
.gallery-item {float:none; margin:0 auto; text-align:center}
targeting the IMG tag would not work because it is nested in another element, so you have to center the parent of the img.
when there is a float, margin:auto will not work properly
If you're not concerned about IE9 compatibility, you can easily achieve this by applying display: flex to the parent <dt> element.
Check out Chris Coyier's Complete Guide to Flexbox if you haven't already read up on this beautiful member of CSS3. I also recommend this article by Paddi McDonnell.
Flexbox underwent some prefixing inconsistencies, so it would be wise to have a fallback style if those users are important to you.
try this:
.gallery {
text-align: center;
}
.gallery dl {
display: inline-block;
float: none;
}
(also clear your browser cache)

IE display: table-cell child ignores height: 100%

I need to dynamically build a table to hold some data.
I've followed the usual approach of using divs with display: table, display: table-row and display: table-cell:
.tab {
display: table;
height:100%;
width: 200px;
}
.row {
height: 100%;
display: table-row;
}
.elem {
border: 1px solid black;
vertical-align: top;
display: table-cell;
height:100%;
background: blue;
}
.content {
height: 100%;
background: greenyellow;
}
<div class="tab">
<div class="row">
<div class="elem">
<div class="content">
Content
</div>
</div>
<div class="elem">
<div class="content">
Longer content that will need to wrap around eventually you know and don't you hate it when things don't end as you expect them octopus
</div>
</div>
</div>
</div>
Or view on Jsfiddle.
In most browsers I get the expected output:
However, in IE8 (and possibly later versions, I haven't tested later versions), I get the following:
The height: 100% set on the div surrounding "Content" is ignored.
According to CanIUse, IE8 should offer full support for the related display properties.
I've looked through a number of similar questions on SO without finding a working solution: most solutions either rely on Javascript (which I'm looking to avoid), use a fixed height (ibid previous) or don't work on IE8.
Unfortunately, the effect of percentage values for height on display: table-row and display: table-cell elements is undefined according to the spec:
CSS 2.1 does not define how the height of table cells and table rows is calculated when their height is specified using percentage values.
So while a browser may claim to offer full support for table layout, certain aspects such as percentage heights may not be consistently implemented across all browsers because there is no correct behavior. You could try raising an issue on Microsoft Connect in hopes that they will change the behavior to be interoperable, but in the meantime you will need to find a different workaround (and even then you can't guarantee the behavior will remain interoperable, even in other browsers).
To make matters worse, I just tested and this affects all versions of IE up to and including 11, which means an IE-specific hack will fall short here. If you need to use a CSS table layout, as evidenced by the fact that you need to support IE8, then a pure CSS workaround is probably not feasible.
For Internet Explorer 8-10 table-cells with height: 100%; have to be wrapped by table-row with height: 100%;.
Html for IE should be like:
table > table-row > table-cell
While other browsers will work properly with
table > table-row
or
table > table-cell
[edit] I reviewed the question again, and noticed You want to set 100% height not to the table-cells, but on the content inside it.
solution 1: So for Internet Explorer content-height is related to closest element with height set in absolute units, such as pixels, em's, if you want to use % height, you may also need to set 100% height on all parent elements, this will be html and body.
working example
solution 2: Simply add
.content {
padding-bottom: 9999px;
margin-bottom: -9999px;
}
.elem {
overflow: hidden;
}
You don't need to set height on Any of the parent elements in this case.
working example.
Hope this helps.

Vertically centering images, within a row, with rows created by clearing floats every 4n+1 elements

I have a question around vertically centering images which I haven't been able to find a solution to and would love to tap some other folks' brains. I am working on this page: http://www.heirloomtileworks.com/newsite/gift-tiles
The usual solutions haven't been working so far (at least not the way I've implemented them). My images are not contained within a div on a per-row basis; rather the rows of images are created by clearing floats every 4n+1 child elements.
The images may be a variety of heights, and the div is also not of fixed height. Images are added via the content manager. Each image is contained within div styled in this way:
#gift-tile-small-container {
width: 120px;
position: relative;
min-height: 100%;
overflow: hidden;
float: left;
margin-right: 30px;
text-align: center;
margin-bottom: 20px;
}
These divs containing images currently flow down the page within a div (#gift-tile-container). So each row is created not by a separate div, but like so:
div#gift-tile-container div:nth-child(4n+1) {
clear: both;
}
I would like each #gift-tile-small-container div to align with the others in its row, so that the vertical centerpoint of each div is aligned with that of it's rowmates.
If you need to see the HTML as well, let me know, although it is written in Textpattern native tags and not normal HTML. It should be fairly self-explanatory. I appreciate your help!
You can try this out. Use inline block for the containers. I reduced the right margin because between each div container, there is white space. I tried this in firebug and it seems to work
#gift-tile-small-container {
display: inline-block;
margin-bottom: 20px;
margin-right: 25px;
min-height: 100%;
overflow: hidden;
text-align: center;
vertical-align: middle;
width: 120px;
}
Again, as I mentioned in the comments, if you need to apply the same style to multiple elements. Use class instead of ID.

dynamic / responsive / liquid layout css

I was wondering if there is an alternative to writing css rather than with css tables to make liquid / dynamic layouts. vinyll really helped me here... simple 3 Column responsive layout
and that is exactly how I need the columns to work, but when I use css tables, it seems I cannot position things inside with margin and padding (I probably could with left and right but relative positing breaks the document flow so I don't want to do that)...heres and example
http://jsfiddle.net/u5nR2/4/
.container{
width:100%;
height:100%;
display: table;
}
div > div {
display: table-cell;
}
.three div{margin-top:100px}/*why doesnt this move?*/
Use padding on the parent element. Margin needs an other element to bounce.
Change
.three div{margin-top:100px}
To
.three { padding-top: 100px; }
Also, change: div > div to .container > div. I assume you only want to select the direct child divs of .container. When you use div > div, the divs inside .one, .two and .three will also be selected. (also mind the vertical-align: top to position the text in the table-cells at the top)
Check your updated Fiddle

Resources