Fill remaining horizontal space (or max-width) AND wrap on min-width - css-float

#fit and #wrap illustrate two different behaviors that I want to have for one element depending on the situation. The element should work like #fit if there is room, but should work like #wrap if there is not enough room.
http://jsfiddle.net/benstenson/dN8VJ/
<div id="print">
Printable
</div>
<div id="fit">
Looks good on same line
</div>
<div id="wrap">
Looks good on new line
</div>
css
body{overflow:hidden;padding:1em;}
div
{
/*display:inline-block;*/
float:left;
height:1in;
margin:.5em;text-align:center;line-height:1in;
white-space:nowrap;box-shadow:0 0 .5em gray;
}
#print
{
width:5in;
background-color:black; color:white;
}
#fit
{
/* when on same line
Size to min-width
OR fill remaining space
(like flexible box style).
Either way is fine.
*/
min-width:3in;
background-color:gold;
}
#wrap
{
/* when wrapped to next line */
/* fill 100% OR to max width */
width:100%;
min-width:3in;
max-width:5in;
background-color:orange;
}

What you're looking for is Flexbox, but most browsers that support Flexbox don't support wrapping. The ones that do are IE10, Chrome, and Opera.
http://codepen.io/cimmanon/pen/lqrGB
<div class="container">
<div id="print">
Printable
</div>
<div id="either">
Looks good on either line
</div>
</div>
.container {
display: -ms-flexbox;
display: -webkit-flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
#supports (flex-wrap: wrap) {
.container {
display: flex;
}
}
.container div {
height: 1in;
margin: .5em;
text-align: center;
line-height: 1in;
white-space: nowrap;
box-shadow: 0 0 .5em gray;
}
#print {
/*-webkit-flex: 1 5in;
-ms-flex: 1 5in;
flex: 1 5in;*/
width: 5in;
background-color: black;
color: white;
}
#either {
-webkit-flex: 1 3in;
-ms-flex: 1 3in;
flex: 1 3in;
max-width: 5in;
background-color: gold;
}

Assuming I've understood your question correctly, I think you can achieve what you want with inline-block.
You'll need to put your content in a paragraph inside another div, like this:
<div class="wrap-or-fit">
<p>This is where your content goes.</p>
</div>
Then just set the min-width and max-width properties on the paragraph, as well as display:inline-block.
.wrap-or-fit > p {
max-width:5in;
min-width:3in;
display:inline-block;
...
}
If the content fits on a single line less than 3 inches wide, the container will expand to be at least 3 inches. If the content is wider than 5 inches, it is forced to wrap within a container of exactly 5 inches.
If the content is between 3 and 5 inches, the container width matches the content width. I'm not sure if that is what you wanted, but that may be the best you can do.
You can see an expanded example showing both narrow and wide content samples, and styling that more closely matching your original example in this codepen.

Related

Dynamic width of div

I would like my div to have the maximum width available, so that the text inside it will wrap if needed when the page is shrunk (just the text should wrap when div will have his max width instead breaking all structure). I found a solution on the internet, but I can't translate it to my specific case. I have looked everywhere and cannot find a way to solve this problem...
All I know that I have to use display: flex and flex: 1 1 auto; somehow, but I can't find good way to do that.
#####EDIT
The problem was that I was using strings without spaces, what was breaking the structure. Adding word-break: break-all; fixed that. Below I put my code. Maybe will be useful for someone
HTML:
<div class="row">
<div class="div1">
</div>
<div class="div2">
<div class="div21"></div>
<div class="div21auto"> fadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfssfadsfsfadsfssfadsfsfadsfssfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfssfadsfsfadsfssfadsfsfadsfssfadsfsfadsfs
</div>
<div class="div21"></div>
</div>
<div class="div1">
</div>
</div>
CSS:
/* important stuff for this example */
.row {
display:flex;
}
.div2 {
display:flex;
flex-direction: column;
}
.div1 {
width: 30px;
height: 90px
}
.div21 {
height: 30px
}
.div21auto {
height: 30px
flex: 1 1 auto;
word-break: break-all;
}
/* other stuff */
div {
padding:1em;
margin:0.2em;
background-color: rgba(0,0,0,0.125)
}
.row {
width:80%;
padding:1em;
overflow:hidden;
}
Maybe set a min-width attribute for that div? That way, that element will always be at least a certain width.

Responsive layout: middle content of centered div with fixed width must become the right column without overflowing

I have a centered div with a width of 700px, with a middle part that must become a right column when viewport is > to some width. I used absolute positioning for that purpose but like this column must be responsive, I don't know its width.
First, I would like to know what is the rule for how behave the width of absolute positioned elements which are out of their relative parent. Absolute positioning should use the width of their relative parent but when the element is out of that parent, the element is shrinked. If there is a word without space, it extends the element accordingly and everything follows. I don't understand how it works and how predict that behavior. It's the same when that element without width is supposed to start overflowing out of its parent.
Then, is there a way to make this column fills the right until it reaches the limit of the window without overflowing (with a little margin-right)? If I fix a big width on that column assuming it will be the max-width that column will achieve in the biggest viewport and use the overflow property to hide what is out of the window, of course, the absolute positioned element is just cut.
I really don't know how to make that responsive because it seems like absolute positioning removes the element from the flow, it is not made for my purpose. Of course, no JS, please. And it must support Internet Explorer since IE8.
The only solution that comes to my mind is to duplicate the content and use display:none/block to switch blocks with media queries but it means redundant code. I tried with a complicated display:table layout until I found that colspan doesn't exist.
(Just so you know, I have a left column too to take into consideration, the reason why I am using a three columns display:table layout. If that's relevant.)
Here is a simplified code:
I didn't put media queries but the aside-on-small-screen is obviously what it should look like on small screens, replacing the aside selector.
main{
overflow:hidden;
}
.colMain{
background-color:green;
margin-left:auto;
margin-right:auto;
position:relative;
width:300px;
}
.aside{
background-color:red;
position:absolute;
top:0px;
left:320px;
}
.aside-on-small-screen{
background-color:red;
}
<main>
<div class="colMain">
<div>stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div>stuff</div>
</div>
</main>
Thank you.
Used flexbox and assigned aside a percentage width. The details are in the CSS portion of Snippet.
Flexbox
justify-content: space-between
order
flex-shrink, flex-grow, flex-basis
Relative units of measurement
Viewport width/height vw and vh
Percentage
em
/* Optional Defaults and Resets */
* {
-ms-box-sizing: border-box;
box-sizing: border-box;
}
html {
font: 400 10px/1 Arial;
width: 100%;
height: 100%;
}
/*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: none;
}*/
body {
font: inherit;
font-size: 160%;
/* background: rgba(0, 0, 0, .2);*/
line-height: 1;
overflow: visible;
width: 100%;
height: 100%;
}
/* Demo Styles */
/* All outlines and backgrounds are for presentational purposes */
/* vw/vh viewport width/height 1vw/vh = 1% of viewport width/height */
main {
overflow: hidden;
/* width: 100vw;
height: 100vh;
background: rgba(0, 0, 255, .2);*/
width: 100%;
height: 100%;
min-height: 35em;
display: table;
}
/* Flexbox layout will automatically keep .aside to the right with the */
/* property justify-content: space-between; which keeps the max amount */
/* of even space between flex-items (which is .stuff and .aside) */
.colMain {
/* display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between; */
background-color: green;
margin-left: auto;
margin-right: auto;
position: relative;
min-width: 99%;
min-height: 99%;
padding: 1em;
display: table-row;
width: 700px;
}
/* Removed absolute positioning in favor of flexbox and a percentage */
/* width. .aside will start dis-proportionally expanding while the viewport */
/* expands. The two columns on the right while begin to shrink in response */
/* to.aside's expansion. All this stretching and shrinking happens when the */
/* elements are at 210px or more (210 is 30% of 700px). This behavior is */
/* accomplished by using flex-shrink, flex-grow, and flex-basis */
.aside {
display: table-cell;
background-color: red;
position: absolute;
top: 1em;
right: 0;
left: 70%;
/* order: 3; */
min-width: 30%;
max-width: 500px;
min-height: 100%;
/* flex-grow: 1;
flex-basis: 210px;*/
outline: 2px solid #7c1b38;
padding: 5px;
}
.aside-on-small-screen {
background-color: red;
}
.stuff {
outline: 2px dotted white;
width: 30%;
max-width: 210px;
min-height: 100%;
position: absolute;
/* flex-shrink: 1;
flex-basis: 210px; */
display: table-cell;
}
#col1 {
left: 1em;
top: 1em;
}
#col2 {
left: 36%;
top: 1em;
}
/*.stuff:first-of-type {
order: 1;
}
.stuff:last-of-type {
order: 2; */
}
/* The HTML shows that the second column (the second .stuff) would be */
/* in-between .aside and the edge of .colMain. Instead of moving it out of */
/* the way in markup (HTML), I used the flexbox property, order. */
<main>
<div class="colMain">
<div id="col1" class="stuff">stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div id="col2" class="stuff">stuff</div>
</div>
</main>
There are three problems in one:
First problem.
How to transform a middle content
<div class="wrapper">
<div>stuff</div>
<div class="aside">Middle content</div>
<div>stuff</div>
</div>
in a right column that expends to the right without overflowing out of the window, when the rest of the past column "wrapper" must be a centered column of fixed width.
<div class="colLeft"></div>
<div class="wrapper" style="text-align:center; width:700px;">
<div>stuff</div>
<div>stuff</div>
</div>
<div class="aside">Middle content now to the right</div>
Absolute positioning doesn't help because without fixed sizes (% or px), it is out of the flow and the content of variable width won't adapt to the situation (and overflow).
This can be easily solved with display table.
Second problem.
Display table/table-cell leads to the second problem.
To make three "columns" with display:table-cell, order is really important. That means the "aside" div must be the last element of its column (the wrapper column in my first snippet) in order to make it an independent cell of a row put to the right. If you don't have to worry about this story of middle content and you just have to switch a content at the end of a div to the right or a content at the beginning to the left, it's already over.
You just have to style colLeft, wrapper and aside of my second snippet with display:table-cell and use another global wrapper with display:table and some other styles like table-layout:fixed and width:100% to do the trick. With a media queries for small screen, you just have to hide the colLeft with display:none.
But if you need that middle content to be a middle content nonetheless on small screens and a right column on large screens, it's a different case.
This can be solved with anonymous table objects and table-header/footer/row-group.
With table-header/footer/row-group, you can reorganize your rows so you can put the "aside" at the end to transform it in an independent cell on large screens and place it in the middle with table-row-group on small screens:
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content</div>
Third problem.
The hardest problem is the centered "column" of fixed width. With table-xxx-group, it is forbidden to put a wrapper around the table-header-group and table-footer-group to set a width of 700px because table-group are row elements and the wrapper will automatically becoming a table object, excluding the "aside" that won't be able to insert itself in the middle with its table-row-group style on small screens.
Without putting a wrapper around the "stuff", you won't be able to control the width of the created anonymous cell on large screens because you can't style something anonymous. So it takes a width of 1/3 like each cell.
main{
display:table;
table-layout: fixed;
width:100%;
}
.colLeft{
background-color:yellow;
display:table-cell;
}
.header,.footer{
background-color:green;
/*no display style > it will create an anonymous cell
object around the header/footer elements*/
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content now to the right</div>
</main>
The solution is to use table-column-group/table-column. You will be able to style your columns and set a width to the middle column even though it is determined anonymously.
The solution
Small screens
.rowTabled{
display:table;
table-layout: fixed;
width:100%;
}
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
.colLeft, .colgroup{
display:none;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>
Large screens
main{
display:table;
table-layout: fixed;
width:100%;
}
.colgroup{
display:table-column-group;
}
.colCol{
display:table-column;
}
.middle{
background-color:green;
width:100px;
}
.left,.right{
background-color:yellow;
}
.rowTabled{
display:table-row;
}
.colLeft{
display:table-cell;
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>

Flexbox: how to get divs to fill up 100% of the container width without wrapping?

I'm in the process of updating an old inline-block-based grid model I have to a newer Flexbox one I created. Everything has worked fine, apart from one little snag, which has become a bit of a dealbreaker:
I have a bunch of CSS-controlled sliders; so there's a containing wrapper with 100% width, and inside is another div: its width is also 100%, but its white-space is set to nowrap. Using inline-block, this meant that the internal divs (which were also set to 100% width) wouldn't be bound by their parents' constraints and wrap onto the next line - they'd just carry on flowing out of the box. This is exactly what I wanted. However, I cannot get this to work at all with flexbox. For reference, here's an image:
And for reference, here's a jsFiddle of the thing working with inline-block: http://jsfiddle.net/5zzvqx4b/
...and not working with Flexbox: http://jsfiddle.net/5zzvqx4b/1/
I've tried all kinds of variations with flex, flex-basis, flex-wrap, flex-grow, etc. but for the life of me I can't get this to work.
Note that I can force it to do what I want in a hacky, inflexible way by setting the .boxcontainer width to 200%. That works for this single example, but in some cases I won't know beforehand how many child boxes there will be, and I'd rather not resort to inline styling on each element if possible.
To prevent the flex items from shrinking, set the flex shrink factor to 0:
The flex shrink factor determines how much the flex item will
shrink relative to the rest of the flex items in the flex
container when negative free space is distributed. When omitted, it is
set to 1.
.boxcontainer .box {
flex-shrink: 0;
}
* {
box-sizing: border-box;
}
.wrapper {
width: 200px;
background-color: #EEEEEE;
border: 2px solid #DDDDDD;
padding: 1rem;
}
.boxcontainer {
position: relative;
left: 0;
border: 2px solid #BDC3C7;
transition: all 0.4s ease;
display: flex;
}
.boxcontainer .box {
width: 100%;
padding: 1rem;
flex-shrink: 0;
}
.boxcontainer .box:first-child {
background-color: #F47983;
}
.boxcontainer .box:nth-child(2) {
background-color: #FABCC1;
}
#slidetrigger:checked ~ .wrapper .boxcontainer {
left: -100%;
}
#overflowtrigger:checked ~ .wrapper {
overflow: hidden;
}
<input type="checkbox" id="overflowtrigger" />
<label for="overflowtrigger">Hide overflow</label><br />
<input type="checkbox" id="slidetrigger" />
<label for="slidetrigger">Slide!</label>
<div class="wrapper">
<div class="boxcontainer">
<div class="box">
First bunch of content.
</div>
<div class="box">
Second load of content.
</div>
</div>
</div>
You can use the shorthand flex property and set it to
flex: 0 0 100%;
That's flex-grow, flex-shrink, and flex-basis in one line. Flex shrink was described above, flex grow is the opposite, and flex basis is the size of the container.
In my case, just using flex-shrink: 0 didn't work. But adding flex-grow: 1 to it worked.
.item {
flex-shrink: 0;
flex-grow: 1;
}
Set the flex-direction: column
You're trying to stack the items in a column rather than a row.
{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

Always wrap at least two items with flexbox

Take a look at this example
It has a flexbox container with flex-flow: row wrap; to wrap all items. This is almost what I want.
When it starts to wrap, item number 6 wraps to the second line:
1 2 3 4 5
6
But always I want to wrap at least two items when it starts to wrap so you'll never have a single items on a line:
1 2 3 4
5 6
While not the most elegant solution, you could wrap the last two elements in another flexbox:
<html>
<head>
<style>
.flex {
display: flex;
flex-wrap: wrap;
}
.flex > div {
flex: 1 0 auto;
padding: 20px;
text-align: center;
}
.flex .flex {
padding: 0;
flex-grow: 2;
}
</style>
</head>
<body>
<div class="flex">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div class="flex">
<div>5</div>
<div>6</div>
</div>
</div>
</body>
</html>
See a pen here: https://codepen.io/anon/pen/prodVd
I figured out a way to do it for inline Elements, however it will behave inconsistently across browsers when used with inline-blocks. Still not a solution, but maybe somebody can figure out a way to make it behave with inline-block elements.
.item {
display: inline;
}
.item::before {
content: ' ';
font-size: 0;
}
.item:last-child::before {
content: '';
}
Here is a Fiddle with it in action.
Here's an approach that should work under the constraint that the width of the element is fixed
Assuming the width is 50px:
.container {
display: flex;
flex-flow: row wrap;
}
.flex-item: {
width: 50px;
display: block;
}
.flex-item:nth-child(even) {
translateX(100%)
margin-left: -100px;
}
.flex-item:nth-child(odd) {
margin-right: 50px;
}
The trick is to basically move the "footprint" of every 2nd element into its predecessor (negative margin), still display it in its original place (translate) and having the predecessor eat the remaining space (positive margin) for the purpose of row-breaking.
You can try to wrap 2 sibling elements with flex container
Based on https://stackoverflow.com/a/30431565/6884587 which did not work due to syntactical and logical reasons, I figured out how to do it for preknown same width items.
.container {
display: flex;
flex-flow: row wrap;
justify-content: center;
/* gap: 5px <-- can be used for spacing */
}
.flex-item: {
width: 50px;
display: block;
}
.flex-item:last-child {
margin-left: -50px; /* consider gap in this value, if applicable */
}
.flex-item:nth-last-child(2) {
margin-right: 50px; /* consider gap in this value, if applicable */}
This way, the last and the next to last item literally end on the same pixel, causing them to wrap line together.
For not preknown, but same width items it is a little more complex, since setting the margin to a percentage value is based on the item parent's width.

Adjust top while maintaining bottom position with CSS

A website I'm working on now is meant to replicate a document that you could print. There is a header, a body, and a footer. All three elements use CSS to adjust the margins and height of each one.
The footer is 0.5in high and must end at least 0.5in from the bottom of the page, but cannot exceed that. Based on other word processors, if the footer is larger than 0.5in, the footer moves up on the page so that it maintains that 0.5in border.
This means that the body will shrink, so I've set it up (I think) so that a larger footer will shrink the body which is the expected behavior.
However, what I want is a way for the footer to adjust its position on the page so that it is always at least 0.5in from the bottom of the page.
Note I'd like the solution to work for any number of pages for one document, so I can't use fixed positions.
I'm including my demo code which works as long as the height is small enough.
<div style="height: 9in;
padding-left: 1in;
padding-right: 1in;
padding-top: 0.5in;
padding-bottom: 0.5in;
background-color: #eee;
margin-top: -0.08in;
margin-left: -0.08in;">
<div style="height: 0.5in"> Nick 1 </div>
<div style="max-height: 9in; height: 9in;">I love stuff.</div>
<div style="min-height: 0.5in; height: 0.5in; margin-top: 0.5in;">Footer</div>
</div>
Look into the CSS sticky footer technique.
The priciple is this:
the content has a bottom padding equal to the height of the footer
the footer uses relative positioning
the footer has a top margin equal to it's own (negated) height
The result is an overlap of the footer over the padding of the content. Since the sizes match the overlap makes the footer "stick" to where the content ends.
This is essentially a sticky footer.
The CSS
.wrap {
min-height:100%;
margin-bottom: -.4in; /* same as footer */
}
.push, #footer {
height:.4in;
}
The HTML
<div class="wrap">
<div></div>
<div></div>
<div class="push"></div>
</div>
<div id="footer">
i would suggest you use native javascript or jquery CSS is not a programming language but javascript will give you more functionality for testing for the conditions needed 
I don't think what you're looking for can be done with CSS only, at least not until flexbox model is more widely supported. If you're using Chrome 24 or higher you can see the code below in action at http://jsfiddle.net/2late2die/bNJZG/1/
.page {
width:8in;
height:10.5in;
background:#fff;
position:relative;
margin:.5in auto;
box-shadow:rgba(0,0,0,.2) 0 0 .1in;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-flex-flow: column;
-moz-flex-flow: column;
-ms-flex-flow: column;
-ms-flex-direction: column;
flex-flow: column;
}
.page .body {
-webkit-flex: 1 0 auto;
-moz-flex: 1 0 auto;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
}
It basically sets the body of the page to be a flexbox item that stretches to take up the entire vertical space between header and footer. You still however would need to manage the height of the body yourself, because if it gets more than the space left between header and footer it will overflow.

Resources