Equal space between flexbox items with wrapping text - html

I have a flexbox with three items (divs) laid out horizontally.
I would like the spacing between these items to be equal.
The problem is, however, that I have breakable text within these divs.
In the example below, the spacing between item 1 and 2 is less than the spacing between item 2 and 3 because the text in item 2 is wrapping without the width of the div being adjusted.
Any suggestions on how to achieve equal spacing while still allowing breaking text?
(Note that the background colors in the example are to illustrate the problem of item 2 being off-center)
.outerContainer {
width: 430px;
}
.container {
display: flex;
padding: 20px;
background-color: tomato;
}
.container > div:not(:last-child) {
margin-right: 20px;
}
.container > div {
background-color: pink;
word-break: break-word;
display: flex;
}
.fig {
border: 2px solid black;
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
margin-right: 5px;
}
<div class="outerContainer">
<div class="container">
<div>
<div class="fig">1</div>
<div>two words</div>
</div>
<div>
<div class="fig">2</div>
<div>some we somewrap </div>
</div>
<div>
<div class="fig">3</div>
<div>some text</div>
</div>
</div>
</div>

You seem to be looking for text-align: justify.
Other possible solutions imply design rather than code, such as exactly what you used to demonstrate the problem: give your elements a distinctive background so they get visually defined by the actual element size, not by the contained text.
Or give them a distinctive border.
You should also consider word-break: break-word (which instead of increasing spaces between words on same row to justify text it simply breaks the word at the end of the available row space).
Could you still state about your elements they're not evenly spaced if rendered like this?
.outerContainer {
width: 400px;
}
.container {
display: flex;
background-color: #888;
padding: 20px;
}
.container > * {
box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 5px 8px 0 rgba(0,0,0,.14), 0 1px 14px 0 rgba(0,0,0,.12);
padding: 20px;
box-sizing: border-box;
word-break: break-word;
color: #666;
}
.container > div:not(:last-child) {
margin-right: 20px;
}
.container > div {
background-color: white;
}
<div class="outerContainer">
<div class="container">
<div>two words</div>
<div>and some short somelongword</div>
<div>some text</div>
</div>
</div>
Apart from the above, the answer to your question is: it's not possible using CSS. To simplify your problem for a clearer understanding, you should consider each element has only 1 row (because when there are more than one rows, the problem is still replicated on each individual row, on some more than on others).
The desired outcome is that each of those rows are rendered in such a way that their content would stretch over an arbitrary allocated space by proportionally changing one or more text properties, in a manner that would make the first letter aligned to the leftmost side of the allocated space and would align the rightmost letter with the right limit of the allocated space.
Technically, you can achieve it by modifying:
the space between words (when the row has multiple words)
the space between letters
the font size
combinations of the above
Using only CSS, you can only proportionally and dynamically modify the space between words, by using:
text-align: justify;
text-align-last: justify;
You can also modify the distance between letters, using letter-spacing property, and you can also modify the font-size but not "dynamically" (so that it fills the desired space exactly) - you could calculate such changes on the fly using JavaScript but chances are no matter what you do, one glove won't fit all sizes.
The rule of thumb here is: try to make it clean and natural.
Leaving technicalities aside and trying to solve the real problem (that "it doesn't look good"), the proper answer is: talk to a designer.
Designers are trained into turning average looking stuff or even bad looking stuff into stuff that looks awesome by adding, removing or changing details an average programmer wouldn't think about or, to be more exact, wouldn't have thought making those particular changes would make the bloody thing look so good.

Related

How to wrap words earlier to justify text up to the last line?

I have a div with a short text that I need to be centered, and justified as much as possible. However, if the text is only slightly longer than the div, only one or two words wrap around, where I would like to have words wrapping earlier so that the last line has approximately the same width as the previous ones.
Here's the code I use (CSS inlined for brevity):
<div style="width: 250px; border: 1px solid black; text-align: center; box-sizing: border-box;">
This text is long enough that a word wraps.
</div>
<div style="width: 250px; border: 1px solid black; text-align: center; box-sizing: border-box; padding: 0 40px;">
This text is long enough that a word wraps.
</div>
Here's an example of what happens:
The second div is what I would like to see, however I can't adjust the padding manually because the text is of variable width.
I'm not sure a pure CSS solution exists, but I hope there's one :) I'm using Firefox (latest) if that's relevant.
If you can nest some element inside div, than you can set the width for that element:
div {
width: 250px;
display: flex;
justify-content: center;
}
p {
width: calc(100% - 30px); /*In addition, you can use percents `width: 30%`*/
text-align: end;
}
<div>
<p>
This text is long enough that a word wraps.
</p>
</div>
<div>
<p>
This text is long enough that a word wraps.
</p>
</div>

How can I position an text to an exactly position

I want to align an text to an exactly position, like 2cm from right not the pre-stabled positions like right, left and center. There's an example: Example
How can I center the Regular, upgraded and exclusive cases like that?
per my comment, here is how the text is centered, but the price tag is included as an inline element with the text.
html
<p class="container">
Text goes here
<span class="block">
$3
</span>
</p>
CSS
.block {
padding: 4px;
background: lightblue;
border-radius: 2px;
margin-left: 4px;
}
.container {
max-width: 400px;
text-align: center;
border: 1px solid;
}
EDIT:
based on the additional information you provided, it's not just aligning text that you were having an issue with, but also layout in general.
I've updated my example to show how you could align elements within a container using text-align: center; and converting the different text/price items to have display: inline-block;.
This is just an entry point to get you started. There are many other ways to layout content with CSS, from floats, flex-box and new CSS Grids. I suggest you review each to determine what is appropriate for your project.
Updated Demo: https://codepen.io/scottohara/pen/oWLxXN

Combine auto, fixed, and percentage width in same HTML table row

I would like to create a table that has 4 columns. 2 of the columns in the table are labels and should auto-size to the widest element. One of the other columns is fixed width and the last should fill the remaining space. My first attempt to create this table looks like this:
HTML
<table style="width:100%">
<tr>
<td class="lbl">lbl:</td> <td class="fluidContent">Expandable Content 1</td>
<td class="lbl">longer label:</td> <td class="fixedContent">Me Fixed</td>
</tr>
<tr>
<td class="lbl">longer label:</td> <td class="fluidContent">Expandable Content 2</td>
<td class="lbl">lbl:</td> <td class="fixedContent">Me Fixed</td>
</tr>
</table>
CSS
table {
white-space: nowrap;
}
td {
border: 1px solid orange;
}
.lbl {
text-align: right;
font-style: italic;
width: auto;
}
.fluidContent {
width: calc(100% - 120px);
}
.fixedContent {
width: 120px;
}
https://jsfiddle.net/vf5p0m82/
Unfortunately this markup yields label columns with fluid width. The "lbl" class cells are treated as though they had a width of 27% specified with the "fluidContent" cells having a width of 46%. What I want is for the "lbl" cells to be as small as possible while still fitting the largest string they contain.
Is there any way to do this how I want simply with tables or is it time to employ the new CSS3 flex-boxes?
Edit: A Solution
Whilst adding another example to this question for clarity I stumbled upon a hack to make it work. If you just give the auto-sized columns a width of 1px everything works out. See here:
https://jsfiddle.net/vf5p0m82/2/
Is there an established/canonical way to do this or is this it?
There might be a more official way to do this, but the thing I've found works is to just set the cell width to 1px. The content size overrides it, so it will just collapse to content size.
.lbl {
text-align: right;
font-style: italic;
width: 1px;
}
By the way, the calc seems to be overridden by table formatting, but it doesn't seem like you need it from what you described.
See it in action: https://jsfiddle.net/vf5p0m82/1/
Ok a flexbox solution: https://jsfiddle.net/vf5p0m82/4/
HTML
<div class="fTbl">
<div class="fluidWrapper">
<div class="shrinkCol">
<div class="lbl">lbl:</div>
<div class="lbl">long lbl:</div>
</div>
<div class="stretchCol">
<div class="fluidCell">Expand Content</div>
<div class="fluidCell">Expand Content</div>
</div>
</div>
<div class="fixedWrapper">
<div class="shrinkCol">
<div class="lbl">longer label:</div>
<div class="lbl">lbl:</div>
</div>
<div class="shrinkCol">
<div class="fixCell" style="width:100px;">Fixed</div>
<div class="fixCell" style="width:100px;">Fixed</div>
</div>
</div>
</div>
CSS
.fTbl {
border: solid magenta 2px;
display: flex;
flex-flow: row wrap;
width: 100%;
align-items: flex-start;
}
.fixedWrapper {
display: flex;
flex: 0 0 auto;
flex-flow: row nowrap;
}
.fluidWrapper {
display: flex;
flex: 1 1 auto;
flex-flow: row nowrap;
}
.shrinkCol {
display: flex;
flex: 0 0 auto;
flex-flow: column nowrap;
}
.stretchCol {
display: flex;
flex: 1 1 auto;
flex-flow: column nowrap;
}
.fluidCell {
border: 2px solid orange;
min-width: 140px;
}
.fixCell {
border: 2px solid orange;
}
.lbl {
text-align: right;
font-style: italic;
border: 2px solid orange;
}
Ok, so here is how you use this CSS generally:
Tables must be divided into separate columns and each column filled independently row by row.
Rows of separate columns must be explicitly given equal heights if they contain items of different heights.
Label/content column pairs are placed in the fixed/fluidWrapper classes so that the labels and content (usually text boxes) wrap together and don't get separated.
It is not possible to have a "colspan" within 1 flex table without decoupling the rows from one another and explicitly setting widths.
I like this approach because it is easy to have the flex items stretch and compress vertically and horizontally to fill a page and wrapping items to respond to narrow screens is fairly simple. It also doesn't require hacky CSS like the table does. I find that HTML tables can be quite cumbersome and unintuitive at times.
I dislike this approach because it is impossible (or perhaps just difficult) to make a row of the table span multiple columns. If there is a wider item it must be placed in a new container and will therefore not share its label width with the items above it. However, it seems that these complaints arise from inherent differences in the table and flex box design objectives and that you must simply choose which approach best suits a given layout.
A search for generating automatic table column widths approximately equal to those of the widest column in any row comes here to this question. If that is what you want to do, try th,td {width: max-content;} in your CSS. Works for me.

Center text around a specific word

In CSS, how can I center text around a specific word?
For instance, let's say I have the following DIV:
<div style="text-align: center;">
Previous Day | Navigation | Next Day
</div>
The text will technically be centered, but the word "Navigation" will NOT be in the exact middle. Rather, the middle will be exactly between the letters "v" and "i". This is because when centering text, the length of the entire string is taken into account.
How can I make the middle instead be between the "g" and the "a", using (preferably) only CSS? Modifying the HTML is also acceptable. As a last resort, I'm willing to use JavaScript, although only if it's kept simple, otherwise it's not worth it to use complex JavaScript for such a simple task.
Fixing the width of the elements containing "Previous Day" and "Next Day" is probably the simplest solution:
<div style="text-align: center;">
<div style="display: inline-block; width: 12em; text-align: right;">Previous Day</div>
<div style="display: inline-block;"> | Navigation | </div>
<div style="display: inline-block; width: 12em; text-align: left;">Next Day</div>
</div>
Fiddle here.
You can wrap your individual items in an HTML tag, like an anchor, and float them to achieve your desired result. Floating the tags places them side-by-side, and giving each item a percentage-width that collectively adds to 100% effectively centers the elements in their container.
Note, there are some pitfalls to using floats. You need to clear the parent div to properly lay out elements following a container with floated children. Also, if the child elements have any padding, this will be added to the percentage width and misalign the children unless you use box-sizing: border-box; on the child elements.
HTML
<div class="container">
Previous Day
<span class="separator">|</span>
Navigation
<span class="separator">|</span>
Next Day
</div>
CSS
.container {
color: white;
margin: 0 auto;
width: 80%;
min-width: 320px;
background-color: black;
overflow: hidden; /* to clear the div */
}
.container a {
text-align: center;
float: left;
width: 32%;
overflow: hidden;
background-color: orange;
}
.container .separator {
float: left;
text-align: center;
padding: .5%;
}
The colors are to show that it is centered in its parent element.
Here's a live demo jsFiddle

Vertical float/overlap issue

I'm making a website and want it to appear as a grid of boxes and rectangles.
I have a 6x6 grid of relatively-alined left-float divs. They work fine and fit neatly in a 900 width wrapper div. If i want a horizontal rectangle, i simply make one of these squares twice as wide (accounting for margins between, but that's irrelevant) and delete the one next to it. No problem.
The issue I have comes in when I want to make a rectangle twice as TALL. it ends up bumping everything left of it in the same row as it a line down. The same happens with a square twice as large (2x2 grid units).
Here's the code in jsfiddle:
http://jsfiddle.net/zucw9/
Essentially, how can I get either 8,9, and 10 to shift up one space, or for 6,7, and 8 to move into that gap, leaving 9 and 10 where 6 and 7 are right now?
http://jsfiddle.net/zucw9/10/
This solution isn't a very good solution but it works.
(I changed some of the names so i could read it better. (.grid_rect_tall became .grid_tall etc. margin-left:10px; margin-right: 0px etc.. became margin: 5px;)
basically you specify a -ve margin-bottom for the tall one and an extra margin so the other elements don't overlap.
.grid_square, .grid_long, .grid_tall
{
float: left;
margin: 5px;
background: #6CC;
}
#main{
position: relative;
width: 905px;
overflow: hidden;
border: 1px solid black;
padding: 5px;
}
.grid_square{
width: 140px;
height: 140px;
}
.grid_long{
width: 290px;
height: 140px;
}
.grid_tall{
width: 140px;
height: 290px;
margin-bottom: -150px;
}
.rbuffer
{
margin-right: 155px;
}
.lbuffer
{
margin-left: 155px;
}
I'd still go with my comment though and use either: http://960.gs or css3 grid layout: http://w3.org/TR/css3-grid-layout
EDIT:- I thought i better put a why to my comment earlier that this is not a good solution. Simply put: if you want to change the layout of the page you will have to change the classes on the items as well as having to change the css.
Also created one with even more elements to show the possibilities: http://jsfiddle.net/zucw9/11/ (or in em instead of px because i was bored. http://jsfiddle.net/zucw9/15/)
The layout is standard, how it should be displayed. I would recommend to use another div which wraps up the dives that appear before the taller div. This is not a very flexible solution though.
Edit: Move
<div class="grid_square">8</div>
<div class="grid_square">9</div>
<div class="grid_square">10</div>
higher in hierarchy after
<div class="grid_square">2</div>
should fix it.
i hope your thinking like below
code:
<div id="main">
<div class="grid_square">1</div>
<div class="grid_rect_long">2</div>
<div class="grid_rect_tall">3</div>
<div class="grid_square">4</div>
<div class="grid_square">5</div>
<div style="clear:both"></div>
<div>
<div class="grid_square">6</div>
<div class="grid_square">7</div>
<div class="grid_square">8</div>
<div class="grid_square">9</div>
<div class="grid_square">10</div>
</div>
</div>