Horizontally center text in row with floats on both sides, with flexbox? - css

Here's a CSS puzzle for you all.
I'm using flexbox in my layout. I have a header with a few buttons on the left side, some text in the center, and another button on the right. Here's an ascii drawing:
[btn][btn2][btn3][ text ][btn4]
Unfortunately, this looks weird because the text isn't centered in the header. What I really want is this:
[btn][btn2][btn3][ text ][btn4]
Ideally, I'd like to continue using flexbox to achieve this because it makes most of the horizontal layout really easy, but I'm willing to fall back to floats and/or positioning if need be.
One problem with positioning the text element absolutely is that long text will under/overlap the buttons on the side. I currently use text-overflow: ellipsis and as a bonus, I would love to continue to if possible:
[btn][btn2][btn3][ long text causes elli... ][btn4]
I'm also okay with adding extra container elements if that helps. Perhaps there's a way to solve this by adding left buttons and right buttons in containers and then ensuring those containers are always the same width?
Edit: I think I took a step in the right direction with this CodePen. It properly centers the text. The only downside is that the h1 needs a fixed or percentage width, and if that width is wider than the space available, it seems to just overlap the neighboring elements.

You came very close to a working sample. I forked your CodePen with a solution that don't require widths of any kind. It's using the power of flex to position elements.
The H1 will always be in the middle, with a width of the same size as the surrounding left-btnsand right-btns, using flex: 1;
You can, of course, specify your H1 to a fixed width as you did, or make it for example flex: 2; to have it take up 50% space instead of 33%.
Here's the fork on CodePen. I've removed unnecessary code.
And the code:
HTML
<div class="wrapper">
<div class="left-btns">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<h1>center me! center me! center me! test woah asdf veasdf veasdf veasdf veasdf ve</h1>
<div class="right-btns">
<div class="box"></div>
</div>
</div>
<h1>center me!</h1>
CSS
.wrapper {
background: green;
display: flex;
margin: 5px;
}
h1 {
flex: 1;
text-align: center;
margin: 5px;
background: yellow;
overflow: hidden;
text-overflow: ellipsis;
white-space: noWrap;
}
.box {
width: 50px;
height: 50px;
margin: 1px;
background: red;
}
.left-btns,
.right-btns {
margin: 5px;
display: flex;
flex: 1;
background: blue;
}
.right-btns {
justify-content: flex-end;
}

Related

Flexbox overflowing container height in IE11

Firstly, let me say that unfortunately I do have to support IE11 still and I don't believe this is a duplicate question, although I have found a few that were kinda similar.
I have a simple modal window which contains 3 flexible components in a column, header, footer and main.
The plan is that the outer box should grow as the content grows, until it is 80% of the height of the screen, at which point the middle section of the modal which is set to overflow-y:auto should get a scrollbar and the main modal will not get any taller.
Here is my markup
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>Content goes here, could get very long</div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
Fairly standard stuff. The modal is set to flex and the header and footer are fixed height. The middle section is set to grow and shrink as necessary. The main thing is that the .modal should never overflow the .modal-wrapper.
I have a jsfiddle set up and it's tested in Chrome, Firefox, Safari and iOS and it's working fine if you drag the bottom right box height up and down you'll see how it is supposed to behave. IE11 though is a mess.
https://jsfiddle.net/jonhobbs/sf6untnt/3/
Now, I have a feeling it may be related to the min-height bug here:
https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview
but I'm not convinced it's exactly that bug because none of the workarounds for that bug seem to work (e.g. using min-height:1px instead of 0, wrapping in another flexbox etc).
Hopefully somebody on SO can take a look at the jsfiddle and see an obvious problem
Maybe if you make it a flex child and use flex:0 1 80%; , it should fixe your trouble with IE :
example
html, body{
height: 100%;
display:flex;
flex-flow:column;
}
.modal-wrapper{
display: flex;
flex-direction: column;
width: 70%;
margin: 0 auto;
flex:0 1 80%;/* IE gets it , because the flow is column */
max-height:80%;/* others such as FF gets it */
background: white;
}
.modal{
display: flex;
flex-glow: 1;/* doesn't exist */
flex/*-shrink*/: 1; /* good enough */
flex-direction: column;
min-height: 1px;
}
.modal-main{
flex: 1;/* good enough */
min-height: 1px;
overflow-y: auto;
padding: 20px;
}
.modal-header, .modal-footer{
flex-grow: 0;
flex-shrink: 0;
height: 60px;
color: white;
line-height: 60px;
text-align: center;
background: dodgerblue;
}
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>This content could get very long so I'm going to put a big long div in it</div>
<div style=" width:100px; height:1000px; background-color:red; opacity:0.1;"></div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
https://jsfiddle.net/sf6untnt/7/

Positioning of elements in a box with Flexbox

I have been trying to make a row of responsive boxes present a nicer look. After lots of effort and googling, I am here to get a word from experts. Please check the image below:
Outermost red is a bootstrap flexible row with display:flex;
Each box, the first of which is represented by green box, has flex: 1 ...;
Until this point, there is no issue and my CSS works perfect on all screen sizes showing all the boxes in same height and width. I just have two issues which I need help on.
Issue 1:
I need that lower part of box (represented by orange border) may always get positioned to the bottom of green box. This way all the buttons will appear in same line.
I tried to use a wrapper div in each box and then set position attribute for wrapper to relative and those of inner divs (yellow & orange) to absolute. Then I set the lower one to bottom: 0px;. But it does not work with flex and needs me to mention fixed height of wrapper which I cannot mention.
Issue 2:
In the box with the blue border I need the text of all lines to be justified except the last line which should be left aligned.
Issue 1
Assign display: flex to the div that is presented by the green box. After that, add align-self: flex-end; to the orange box. The orange box should now be displayed at the end of the green box.
Issue 2
Use the following fix to achieve what you want:
.blue-box {
text-align: justify;
-moz-text-align-last: right;
text-align-last: left;
}
The problem is that this wis not supported by Safari on Mac and iOS devices. You would have to add more markup to also cover Safari. An example would be to wrap each text line into a p tag if it's possible. Then you could do this:
.blue-box p {
text-align: justify;
}
.blue-box p:last-child {
text-align: left;
}
Please report back if the fixes do work for you or not.
The best way to solve this is to use flexbox.
.promo-boxes {
width: 100%;
display: flex;
justify-content: space-between;
background-color:black;
}
.promo-box {
width: 100px;
border: solid 1px #ccc;
background-color:red;
display: flex;
}
.btns-wrapper {
margin-top: auto;
align-self: flex-end;
}
<div class="promo-boxes">
<div class="promo-box">
<div>test 2</div>
<div class="btns-wrapper">
<button>
subscribe
</button>
</div>
</div>
<div class="promo-box">
<div>
test 3
</div>
<div class="btns-wrapper">
</div>
</div>
<div class="promo-box">
<div>
test 4 <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
loooong
</div>
<div class="btns-wrapper">
</div>
</div>
</div>

CSS - aligning wrapped floating divs to the center

I am trying to create something like a gallery that shows different number of images per row based on the width of the browser. This has already been achieved using overflow: hidden in the outer div and float: left in the inner div.
However, what happens with this is that my images are always aligned to the left, leaving alot of whitespace on the right. How do I make it such that the gallery is always centered in the screen no matter how many images there are per row.
My code is on http://codepen.io/anon/pen/KzqAs
Thank you very much. :)
How about this: http://codepen.io/anon/full/mtBbF
HTML
<div class="container">
<div class="red box">red</div>
<div class="blue box">blue</div>
<div class="black box">black</div>
</div>
CSS
body{
text-align:center; /*You would need to define this in a parent of .container*/
}
.container{
display: inline-block;
margin: 0 auto;
text-align: left;
}
.box {
width: 300px;
height: 300px;
float: left;
}
Demonstration
You need to use an id(or class) on the main div. Set width: 300+px and margin: auto
Also your boxes should be with display: inline-block to allow them to begave "inline"
I have changed colors of the boxes a bit for better visibility.

Fixed width columns with fluid gutters

I know this can be done with columns, but I have to support IE.
I'm trying to get to a layout whose columns are all fixed width, with the gutters being fluid.
I couldn't get this to work with floats, so I settled on using justified inline-block items:
HTML
<div class="wrapper">
<div></div>
<div></div>
<div></div>
<!-- more divs... -->
</div>
CSS
.wrapper {
text-align: justify;
}
.wrapper div {
width: 100px;
display: inline-block;
}
This works wonderfully, but the last row of divs are all aligned to the left: http://jsfiddle.net/EsHh3/
The only solution I found is to add additional unnecessary divs: http://jsfiddle.net/EsHh3/1/
I feel uncomfortable about this, so I'd like to know if there are any other options.
Please don't tell me not to re-invent the wheel. I have not found any fluid grid system that supports fluid gutters.
For what you want to do, I'm afraid a CSS only solution is not available at the moment, much less if you want it to work in IE8.
Since you want to have (a) items that are in the HTML source as a list (b) a variable number of columns depending on available space (c) column spacing depending on width of container I think the solution you'll need would have to employ at least a bit of javascript.
Consider on of the frameworks proposed in the other answers. One I've worked with and could do what you want is Masonry (or the for-pay bigger brother Isotope). (There's also a non-jQuery version of Masonry). You'll have to come up with a function that when the page is resized, recalculates the desired gutter and reconfigures the framework. Something along the lines of calculating x = how many items would fit per line based on the container width and item width and then dividing the remaining space by x-1.
If you want to stick with the idea of adding extra DIV's to the markup, an alternative would be to listen to resize events, and add DIVs as needed based on the width and how many items would fit per line.
ORIGINAL ANSWER, which failed to fit all the criteria.
Since you're relying on text-align: justified the reason the last line doesn't expand to the full width is because there's no line break at the end of it. So to accomplish that we add an extra element with an wrapper:after {} rule, that is also an inline block with a width of 100% so it guaranties a line break.
See fiddle
The CSS ends up something like:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
}
.wrapper div {
width: 100px;
display: inline-block;
}
.wrapper:after {content: ''; width: 100%; display: inline-block; background: pink; height: 2px; overflow: hidden}
Note that the pink background is there so that you can see where the element is. You might need to play with the border/margin/padding of that extra element or the wrapper so that content that comes after wrapper doesn't gain extra margin. In chrome unfortunately there's a slight missalignment of the last row items, possibly because of the extra space between the last DIV and the fake element.
Hey I don't know why you want a fluid gutter, but I have a simple grid sample which you might want to have a look and if you want to see the css then click the SCSS on the codepen site. Also, if you are learning then this sample is very good start point for how to make your own grid. Also, to avoid yourself reinventing the wheel you might want to try different grid frameworks out there. Just google css grid frameworks.
you can try this:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
moz-column-count: 3;
-moz-column-gap: 20px;
-webkit-column-count: 3;
-webkit-column-gap: 20px;
column-count: 3;
column-gap: 20px;
}
Updated URL
This is how I would go about it: http://codepen.io/jeremychurch/pen/wmtJz
.container {
display: table;
width: 100%; }
.cell {
display: table-cell; }
.content {
width: 15em;
margin: 0 auto; }
<div class="container">
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
</div>

How do you set a floating div's width to take up remaining space without pushing other divs down?

For part of a layout I want to make, I want to use three divs, all floating next to each other. The Left and Right have a max-width set, which works fine, but I want the middle div to expand its width to fill the remaining space. To clarify, the left and right divs may have a width of anywhere from 0px to the max-width, depending on what is in each, and I want the middle div to expand its width so that it takes up the rest of the space not used by the divs on either side.
The problem it's having now is that if there is a lot of content in the middle div, it's expanding and pushing the right div off to the next line instead of keeping it up with the other two.
Here's the css I have so far:
#left-column {
width: auto;
max-width: 200px;
height: auto;
float: left;
}
#middle-column {
float: left;
width: auto;
}
#right-column {
width: auto;
max-width: 200px;
height: auto;
float: right;
}
...and the HTML:
<div id="left-column">...</div>
<div id="middle-column">...</div>
<div id="right-column">...</div>
I think that this can be accomplished using a three-column, single-row table, but I absolutely do NOT want to use tables - I want to accomplish as much as possible by using pure css.
Thanks!
Classic Floats
If you order it:
<div id="left-column"></div>
<div id="right-column"></div>
<div id="middle-column"></div>
and you float the left column left, and the right column right, the middle column should fill in the remaining space. You will have some issues with margins, borders and paddings though.
Flexbox
If you don't need to support older browsers, you can use flexbox. With flexbox, this sort of structure becomes much simpler, and the markup doesn't need to change.
You will need to be able to select the parent element, so for the purposes of this demo, the code will be wrapped by <div class="wrapper">.
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
}
.left {
background-color: red;
width: 100px;
}
.middle {
background-color: green;
flex: 1;
}
.right {
background-color: blue;
width: 100px;
}
<div class="wrapper">
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
</div>
The height and widths are added explicitly so that the <div>s are visible. With actual content, the columns would automatically adjust.
I don't want to dredge up an old thread here but I was looking for a solution to my own problem and came across this and I thought I'd better share with Francisco...
Tables are a terrible idea for positioning layout, the main problem is that before a table will show/render in the browser it has to render it's </table> tag.
Could you imagine if Facebook's column content used a table for it's layout, it would take ages for it to render anything to the screen when checking your timeline for instance!
Another issue is that tables behave extremely differently in each browser.
Basically: <table> for layout = NO!, <table> for listing out rows of data or information = YES!

Resources