css Flex fluid widths - css

I have a somewhat complicated problem. I have to present ingredients of recipes in 2 columns. One column is the ingredient quantity and measuring unit and on the right it is the ingredient.đ
Structure wise one ingredient get's 2 DIV-s, left and right part
.recipeIngredient {
display: flex
}
.unit {
flex: 1: border-right:1 px solid #666;
padding-right: 3%;
text-align: right;
}
.ingredient {
flex: 2;
padding-left: 3%;
text-align: left
}
<p class='recipeIngredient'>
<div class='unit'>1 kg</div>
<div class='ingredient'>flour (it should be wholegrain type</div>
</p>
<p class='recipeIngredient'>
<div class='unit'>2 pieces of big</div>
<div class='ingredient'>tomatoe</div>
</p>
There can be numerous rows.
I did this with floats and widths, but it doesn't play out well, so I am trying to use flex. In my example left column is 33% width and the right one is double the size. That is usually ok. But sometimes I get a longer line in the left column and sometimes in the right.
How can I make the widths fluid in a way if all of my rows in column one are short and the right rows are longer that have to be broken into two, the width proportions would change, giving only the needed space of the left or right column?
And another problem here is that I want to give priority to the left column if content is too long of both columns, the right one should break, not the left one, because it looks stupid if the column is like this:
up to 1 | wholewheet flower
kg
I would rather have the wholewheet flower would break and left side would keep together if possible. And if there is room on the left side, shrink column and give more space to the right one.
I am not sure if this is possible at all, because I have cells row based not column based and all should adapt acording to the whole, not each one separately, I would like all ingredients to be aligned (left side right justified and right side left justified).
There is one other problem I do have with my code. If I like to vertical align ingredient to the bottom instead of top so that it would read
up to 1 |
kg        | wholewheet flower
It looks better. But using flex to put it on bottom shrinks right cell to the content so the divider line is missing on top.
PS - Maybe this could be better done without using CSS grids? But I guess my structure is not the best for it, but it is needed for google smart cards.

Using table:
section {
display: table;
table-layout: fixed;
border: 1px solid;
max-width: 200px;
}
.recipeIngredient {
display: table-row;
}
.unit,
.ingredient {
display: table-cell;
outline: 1px solid;
padding: 5px;
}
.unit {
white-space: nowrap;
}
<section>
<div class='recipeIngredient'>
<div class='unit'>1 kg</div>
<div class='ingredient'>flour (it should be wholegrain type</div>
</div>
<div class='recipeIngredient'>
<div class='unit'>2 pieces of big</div>
<div class='ingredient'>tomatoe</div>
</div>
</section>

Related

Using float left and right, right container still slides under left contain on a mobile device

I have this issue that is only affecting my site when it is displayed on a mobile device.
On a desktop browser, it looks like this:
My Wonderful Game X
PriceHistory
However, on mobile, the Close 'X' button appears under the title, like this:
>
My Wonderful Game
X
Price History
My CSS:
#TitleContainer {
padding-bottom: 10px;
float: left;
}
#CloseControl {
padding-right: 10px;
float: right;
}
.PriceHistory {
clear: both;
}
HTML:
<div id="GameDetailsSection">
<div id="TitleContainer"> My Wonderful Game </div>
<div id="CloseControl"> <button onClick={hide}> X </button></div>
<div className="PriceHistory"> Price History </div>
</div>
Is there a way to make it so the "X" (#CloseControl) is always in the top right?
Thanks
If the added width of both elements exceeds the screen width, the second one will be displayed under the first one. There are two thing you might do:
1.) Change the order, so that at least the right-floated "X" always stays on top.
or (probably better):
2.) Define the width of the left-floated element as follows (note: This example is based on a width of 30px for the "X" element - just change that according to your needs!): width: calc(100% - 30px). That way the left-floated element always is 30px less wide than the full width, which would allow a 30px wide element (the "X") to float right of it.
Note: Don't forget to use box-sizing: border-box on both elements to include paddings and borders in the width calculation.

Horizontally centering elements to their container while avoiding overlap

I ran into an interesting CSS problem today, and I have been wracking my brain trying to solve it.
This is similar to the trivial problem of "a row of three elements, with a left, a right, and center," which can be solved easily with flexbox — but it has a couple of caveats that make it (I think) an impossible layout without JavaScript.
The desired goal
Consider a row-like container element and three children, "left", "right", and "center". The children may be of varying widths, but they are all the same height.
"Center" should try to stay centered relative to its container — but the three sibling elements must not overlap, and may push outside the container if necessary.
The markup, then, might look something like this:
<div class="container">
<div class="left">I'm the left content.</div>
<div class="center">I'm the center content. I'm longer than the others.</div>
<div class="right">Right.</div>
</div>
The CSS is where the challenge is.
Examples of what should happen
For wide containers, "center" is centered relative to the container (i.e., its siblings' widths do not matter), as in the image below; notice that midpoint of the "center" element matches the midpoint of the container, and that the left and right "leftover" spaces are not equal:
For narrower containers, "center" abuts the widest sibling, but it does not overlap. The remaining space is distributed only between the narrow sibling and the "center" sibling. Notice also that the container's midpoint, indicated by the caret, is no longer the same as "center's" midpoint:
Finally, as the container continues to shrink, there's no other option but to have all three elements lined up in a row, overflowing the parent:
My attempts to solve this
Surprisingly, I haven't found a good way to implement this in pure CSS.
You'd think flexbox would be the winner, but you can't really get flexbox to do it right: The space-between property distributes the space uniformly between the elements, so the center element doesn't actually end up centered. The flex-grow/shrink/basis properties aren't especially useful for this either, since they're responsible for controlling the size of the child elements, not for controlling the size of the space between them.
Using position:absolute can solve it as long as the container is wide enough, but when the container shrinks, you end up with overlap.
(And float layouts can't get within a mile of getting this right.)
I could combine the best two solutions above, and switch between them with a #media query — if all of the widths were known in advance. But they aren't, and the sizes may vary widely.
In short, there's no pure-HTML-and-CSS solution to this problem that I know of.
Conclusion, and a JSFiddle to experiment with
I created a JSFiddle that shows both the desired goal and a few non-solutions. Feel free to fork it and experiment. You can simulate the container resizing by grabbing the bar to the left of the content and dragging it. You are allowed to rearrange/restructure the HTML and CSS, if rewriting it gets you closer to a working answer.
https://jsfiddle.net/seanofw/35qmdnd6
So does anyone have a solution to this that doesn't involve using JavaScript to intelligently distribute the space between the elements?
With flexbox you should be able to solve that, by giving the left/right elements flex: 1 and the right text-align: right.
The main trick is flex: 1, which will make them share available space equally.
For more versions, see this brilliant question/answer, flexbox-justify-items-and-justify-self-properties
Fiddle snippet
Stack snippet
body {
font: 14px Arial;
}
.container {
display: flex;
border: 1px solid #00F;
}
.container > div > span {
display: inline-block;
background: #36F;
white-space: nowrap;
padding: 2px 4px;
color: #FFF;
}
.container > .center > span {
background: #696;
}
.container .left,
.container .right {
flex: 1;
}
.container .right {
text-align: right;
}
.center-mark {
text-align: center;
font-size: 80%;
}
.note {
text-align: center;
color: #666;
font-style: italic;
font-size: 90%;
}
<div class="container">
<div class="left">
<span>
I'm the left content.
</span>
</div>
<div class="center">
<span>I'm the center content. I'm longer than the others.</span>
</div>
<div class="right">
<span>
Right.
</span>
</div>
</div>
<div class="center-mark">^</div>
<div class="note">(centered marker/text)</div>

Make sure a float:right element is vertically aligned to the top, even if next to a float:left element

I ran into a small problem with floats that i demonstrate in this fiddle.
I have a DIV which floats to the left, whose width is dynamic (unknown). I have another one that floats to the right in the same block, width dynamic as well.
The problem is that if the width of the first block extends so that it would collide with the right float, the right float will (correctly) drop downwards to make sure no collision is happening. However, i want it to stay on top (vertically, that is - not in terms of z-index).
Basically it seems that the text is prioritized as to "displace" the block on the right side. This should be the other way around, but with the text on the left using up the available space on the topmost line before it even starts to wrap.
I guess the solution is fairly simple. Its just that it doesn't come to my mind at all and any searches i did didn't find me what i was looking for.
You might want to try using css tables/ Just create both elements and make it a table, then make your right and left elements table-cells:
#wrapper {
display: table;
width: 100%;
}
#leftside, #rightside {
display: table-cell;
width: 50%; /* Both sides will be rendered on one line */
vertical-align: top;
}
/* Position elements within the cell */
#leftside { text-align: left; }
#rightside { text-align: right; }
#leftside > div, #rightside > div {
display: inline-block;
text-align: left; /* Reset text alignment */
}
Explanation: The table structure will keep the elements in one line with width 50%; The inner elements (divs in this case) will be inline-blocks so that they can be aligned left or right. Now when one of the inner divs exceeds the max width of 50% it will just make the other 'cell' side smaller
Float the label div inside the title div, that will wrap the title text around the label regardless of the width of either.
<div class="infoBox">
<div class="inner">
<div class="entry">
<div class="title">
<div class="type">
LABEL
</div>
If this text is longer, the LABEL will drop downwards.
I would like to have the LABEL float right (as it does here) but also be at the top of the block.
</div>
</div>
</div>
​

CSS - Header tag with image filling remainder of column

Hopefully the good people at Stackoverflow can help me today - I basically drank far too much beer last night watching the football and my brain has stopped working.
I'm doing a responsive theme, 3 column layout with H2 tags at the top of each. I need to have a background image filling up the remaining space within the column. I've mocked up an image below to demonstrate what I'm on about;
If the background was a block colour I'd probably display the H2 inline and apply the background-colour to that as well, blocking out the image behind it on the containing div.
As you can see though, the mottled background means that technique doesn't work very well, notice the obvious line above the text;
I've been trying all sorts - there must be some clever way of doing this and I hope you can help me!
Thanks for reading!
Robbie.
EDIT Ok, in the end I used a combination of the two answers below, but accepted the answer splitting the header tag into two divs and floating the first left (as I wouldn't have thought of that). It didn't work on it's own, but by giving the left floated div a background the same height as the double lines and tiling it on the x-axis (rather than giving the whole element the background), I was able to cover up the lines under the text without it jarring with the background.
Image:
HTML:
<h2>
<div class="h2-text">Aha!!</div>
<div class="h2-lines"> </div>
</h2>
And CSS;
.h2-text {
padding-right: 5px;
background: url(../images/footer-lines-overlay.png) repeat-x 0 20px;
float: left;
}
.h2-lines{
background: url(../images/footer-h2-lines.png) repeat-x 0 20px;
}
Thanks very much!!
Overshot the Ballmer Peak, I see.
Anyway, one possible solution is to use floating elements:
<h2>
<div style="float: left;">My Header Tag</div>
<div style="background: whatever;"> </div>
</h2>
A simple solution would be done using the following structure:
<h1><div><span>The text</span></div></h1>
Add this style
h1 {
background: url('the-noise-background');
}
h1 div {
background-image: url('the-double-lined-background');
}
h1 div span {
padding-right: 20px;
display: inline-block;
background: url('the-noise-background') -20px -10px /* Fine tune those pixels so it matches the original position */;
/* use required line-height and other stuff to full cover the lines */
}

CSS 3 columns, why is the third column taking over the other 2?

Here is the smallest amount of code that clearly illustrates my problem:
<html>
<body>
<div style="float: left; width: 200px;">One</div>
<div style="float: left; width: 200px;">Two</div>
<div style="background-color: #f0f;">Three</div>
</body>
</html>
The first 2 divs are supposed to be 2 left columns. The 3rd should take up the rest of the page. Eventually, I'm going to add options to hide and show the 2 columns on the left.
But, why is the color purple extending all the way to the browser's left edge? I am trying to get it to start at the word "Three".
You need to 'float' the third column as well. Then add a clearing block after it.
See Block formatting contexts by W3C:
In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
You can avoid that by forcing creation of new blocking formatting context:
<div style="background-color: #f0f; overflow: hidden">Three</div>
If overflow: hidden is not an option for you (popups etc.), here is another technique:
<div class="has-columns">
<div class="column first">...</div>
<div class="column second">...</div>
<div class="column third">...</div>
</div>
.has-columns {
padding-left: 400px; /* padding reserved for floats */
}
.column.first {
width: 180px;
margin-left: -400px;
float: left;
}
.column.second {
width: 180px;
margin-left: -200px;
float: left;
}
I have to admit, the behavior of floats can be confusing sometimes.
Depending what you want to have happen when columns one and two disappear, you have a few options:
1) If you want column 3 to expand and fill all the remaining space simply add overflow: hidden; to the styles of the third div. It will flow next to the two floated divs just as you expect.
2) If you want the third column to keep it's size and shape no matter what happens to columns 1 and 2, float it to the right, with a set width such as float: right; width: 200px; and it will no longer be effected by the other two, but stay 200px at the right edge of the container.

Resources