Please note that it's not a simple "how do I get XXX" question. I can achieve the look I'm going for but I'm surprised on how. Hence, I fear that I'm doing it in a bad way.
As shown in this fiddle, the text inside the divs is left aligned and the CSS text-adjust isn't effective. I suspect it's because the width of the div somehow is void, because setting the width to e.g. 15% for each numeric cell causes the expected behavior.
Of course, setting the width collides with the very point of enjoying flex, so that's not the right way to go. I'm reaching the requested look by applying justify-content but my understanding is that controlling the alignment that way (from the container div imposing placement on the child element) is supposed to be applied on blocks (i.e. div'ish not span'ish stuff). Am I confused/mistaken in this regard?
I've googled it but drowned in gazillions of posts on how to align children in a flex container. The closest relative to my issue is here but I don't really understand how it differs from what I'm trying to achieve. Also, it doesn't give me understanding of where my thinking went wrong (undoubtedly it did but I expected it not to).
Is it recommended to always have a non-flex'ish div inside the cell'ish div to encapsulate the text mass inside it? It seems like bad HTML markup.
div.data-row-cell {
display: flex;
padding: 3px;
}
div.data-row-value {
text-align: right;
flex: 1;
}
<div class="data-row">
<div *ngFor="let data of data"
class="data-row-cell data-row-value">
{{data}}
</div>
</div>
In order to understand how flex works, we should do some testing. Therefore I will build some example.
First its important to know that the default behaviour of a flex container direction is set to row. That means that all child elements inside a flex container will be placed next to each other as long as possible.
Also we don't think in left or right anymore when using flexbox. We no think in main axis and cross axis.
The main axis is the direction, the child elements are layed out. So per default it would be from left to right.
The cross axis would then be from top to bottom.
Next it is important to know, that by default the child elements inside the flex container only take as much space as needed.
/* just for some nice looking */
* {
font-family: sans-serif;
box-sizing: border-box;
}
.flex-container {
display: flex;
width: 100%;
padding: 1rem;
background: #666;
}
.flex-item {
padding: 0.5rem;
font-weight: bold;
color: white;
}
.r {
background: red;
}
.g {
background: darkgreen;
}
.b {
background: blue;
}
<div class="flex-container">
<div class="flex-item r">blue</div>
<div class="flex-item g">red</div>
<div class="flex-item b">green</div>
</div>
Since now we know the default behaviour of the flex container and the child elements, lets see what we have to do to make text-alignment work.
One way could be to stretch the child elements, so that the text inside has enough space for alignment.
We could do this with the property flex-grow for the child elements:
/* just for some nice looking */
* {
font-family: sans-serif;
box-sizing: border-box;
}
.flex-container {
display: flex;
width: 100%;
padding: 1rem;
background: #666;
}
.flex-item {
padding: 0.5rem;
font-weight: bold;
color: white;
}
.r {
background: red;
}
.g {
background: darkgreen;
}
.b {
background: blue;
}
/* Updated content */
.flex-item {
flex-grow: 1;
}
.r {
text-align: left;
}
.g {
text-align: center;
}
.b {
text-align: right;
}
<div class="flex-container">
<div class="flex-item r">blue</div>
<div class="flex-item g">red</div>
<div class="flex-item b">green</div>
</div>
So in your case, we could remove the display: flex from the .data-row-cell class and just add some flex-grow: 1
Please see my updated fiddle:
https://jsfiddle.net/7wfm1s0j/
I hope it helps :-)
Normally a when you call the parent display: flex then his children contain a default behavior that means it's default value get flex-direction: row. in a flexbox row element not work text-align property, it's work when you call the flex-direction: column here the solve your problem some example:
**your code**
div.data-row-value {
text-align: right;
flex: 1;
border-color: lightblue;
}
/*my example 1 */
div.data-row-value {
/* text-align: center; */
flex: 1;
border-color: lightblue;
justify-content: flex-end;
}
/*my example 2 */
div.data-row-value {
text-align: right;
flex: 1;
border-color: lightblue;
flex-direction: column;
}
/*my example 3 */
<div *ngFor="let data of data" class="data-row-cell data-row-value">
<div style="width:100%">{{data}}</div>
</div>
Related
I'm trying to design a simple and responsive homepage layout. To make things more efficient and easy (hopefully) I'm using flexbox.
My idea is to have a centered main title ("This is Flexbox") with two clickable buttons below it ("Try it" and "About").
I also added a media query to try and adapt the flexbox settings differently in screens that are below 640px width, but I just can't make flexbox work both ways; more specifically, I'd like the two buttons to stack on top of each other as columns when the screen width is below 640px, as well as modify their sizes and keep them centered.
Now, my problems are:
link color does not work and remains blue-ish instead of orange;
the title box is as large as the entire page and not as the text it contains;
the media query, with which I tried to use flexbox differently in screens that are 640px or larger, seems to be "overridden" by the flexbox commands outside the media query itself;
the command: flex-flow:column does not work.
CodePen code link
a {
text-decoration: none;
}
body {
font-family: 'century gothic', sans-serif;
background: black;
box-sizing: border-box;
}
#media(min-width:640px) {
.buttons {
display: flex;
flex-flow: row;
justify-content: center;
color: ivory;
margin: 0 100;
}
.buttons .btns {
border: solid red 1px;
background: #ff7b25;
padding: 10;
border-radius: 10px;
color: ivory;
}
.buttons .btns:hover {
background-color: white;
color: #ff7b25;
transition: .5s;
}
}
.buttons {
display: flex;
justify-content: center;
flex-flow: column wrap;
border: solid red 1px;
margin: 10 50;
color: ivory;
}
.buttons .btns {
text-align: center;
border: solid red 1px;
background: #ff7b25;
border-radius: 10px;
color: ivory;
margin: 10px;
}
.buttons .btns:hover {
background-color: ivory;
color: #ff7b25;
transition: .5s;
}
.title {
border: solid red 1px;
margin-top: 150px;
display: flex;
justify-content: center;
}
.title .t1 {
border: solid red 1px;
background: #2f2a2a;
padding: 5 10;
color: ivory;
}
.title .t2 {
border: solid red 1px;
color: ivory;
letter-spacing: 3px;
font-style: oblique;
background: #ff7b25;
padding: 5 10;
}
<div class="title">
<div class="t1">
<h1>This is</h1>
</div>
<div class="t2">
<h1>FLEXBOX</h1>
</div>
</div>
<div class="buttons">
<div class="btns">
<h3>Free trial</h3>
</div>
<div class="btns">
<h3>About</h3>
</div>
</div>
Link colors:
You need to add the color attribute in your a selector, not in .btns.
Title box:
In order to be centered properly, your flexbox should be as wide as the site, with its elements centered, that's correct. Just apply no styling to it so its width isn't visible. If you need a box around the children, you should wrap them in a container (which then becomes the flex item).
Media query:
Your CSS order is wrong, put the #media at the end, as it is, you apply the #media rule and then always override it with your non-specific CSS further down.
let me tackle your problems one after another:
link color does not work and remains blue-ish instead of orange
By adding color: inherit; to a {} you can make it respect the color. (Read more about cascade to learn more).
the title box is as large as the entire page and not as the text it contains
Naturally, since it is a „block” element (instead of an „inline” one). You can remove the border definition from .title to make it look like you expect?
the media query, with wich I tried to use flexbox differently in screens that are 640px or larger, seems to be "overridden" by the flexbox commands outside the media query itself
In CSS the later definitions overwrite earlier ones.
Try moving the media query towards the end of the file.
the command: "flex-flow:column" does not work.
Could you elaborate?
I'm only going to go into flex-flow, because I see that the other answers are pretty well answered.
flex-flow is shorthand for two CSS properties, flex-direction, and flex-wrap. I believe that just putting column flex-flow won't be sufficient. I think you need to add another value wrap or no wrap.
flex-flow: column wrap;
I've recently starting using flexbox and this is the first problem I've run into. I want my .wrp class below to remain display: inline-block; but one line seems to disable this value. That line is: flex-direction: column. When I remove that line my .wrp class starts behaving like an inline-block element again but then of course it loses it's flex-direction value. Is there a simple solution that doesn't require restructuring my HTML too much to keep the flex-direction behavior of flexbox but also keep the inline-block behavior on .wrp?
.contr {
display: flex;
flex-direction: column; /* this line seems to be breakig my display on .wrp */
justify-content: center;
height: 10rem;
background-color: #eee;
}
.wrp {
display: inline-block;
height: 5rem;
background-color: #ddd;
}
p {
width: 100%;
background-color: #ccc;
}
<div class="contr">
<div class="wrp">
<p>I want this paragraph to stretch to fit it's content. Not full width.</p>
</div>
</div>
You can't have an inline-block element within a flex. It looks like you may be looking for display: inline-table:
.contr {
display: flex;
flex-direction: column; /* this line seems to be breakig my display on .wrp */
justify-content: center;
height: 10rem;
background-color: #eee;
}
.wrp {
display: inline-table;
height: 5rem;
background-color: #ddd;
}
p {
width: 100%;
background-color: #ccc;
}
<div class="contr">
<div class="wrp">
<p>I want this paragraph to stretch to fit it's content. Not full width.</p>
</div>
</div>
Hope this helps! :)
Can i get the height of the previous element using only CSS?
I am using calc() function to set dynamically height of the div B.
#b{
height:calc(100vh - heightOfPreviousElement);
}
I need to know the height of the previous element.
what i know is that, 100vh is equal to 100% of the screen height.
I used the code in the answer below.Using flex,
I have one problem. The height of the color orange become smaller.
You can easily achieve the effect you're looking for using flexbox. The trick is to allow the blue container (the one with the flexible height) to grow in size whenever the need arises, using flex: 1 1 auto, which is simply a shorthand for:
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
See proof-of-concept code snippet below:
body {
padding: 0;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
flex-wrap: no-wrap;
align-items: center;
justify-content: center;
height: 100vh;
}
.wrapper > div {
width: 100%;
}
#c1 {
background-color: #880015;
color: #fff;
height: 60px;
margin-bottom: 10px;
}
#c2 {
background-color: #ff7f27;
}
#c3 {
background-color: #00a2e8;
flex: 1 1 auto;
margin-bottom: 10px;
}
<div class="wrapper">
<div id="c1">height: 60px</div>
<div id="c2">height: auto (determined by content?)</div>
<div id="c3">flexible height</div>
</div>
No you can't select a previous element in CSS.
You might be interested in JQuery Prev OR Parents method for selecting previous element and apply height using .css() method?
I am faceing very strange behaviour of flexbox for my page layout.I am using FontAwesome to render certain symbols.
Basically, I have 2 flexbox items inside another flexbox item, and these child items render wider than parent item.
1) I have a .content__header object, which is rendered as a flexbox object inside another series of flexbox objects.
2)The .content__header object contains 2 child objects: .breadcrumb and .page_tools. These child objects are rendered as flex items as well.
3) Inside the .breadcrumb object, I have some span objects (.breadcrumb__test) who's content is replaced by a FontAwesome icon. The replacement is done using absolute positioning of the ::after pseudo-element.
4) When I remove all .breadcrumb__text HTML elements or just remove the .breadcrumb__text::after definition from my stylesheet - which defines the use of the FontAwesome font - the child objects (.breadcrumb and .page_tools) render at their correct width. So I guess it has something to do with the replacement by a FontAwesome icon.
.breadcrumb__text::after {
font-family: "FontAwesome";
font-weight: 400;
}
Visual representation of the issue
The green line indicates the difference between the parent width and it's actual contents.
Code & Fiddle below.
Browser: Google Chrome 47.0.2526.106 m
Fiddle:
https://jsfiddle.net/44gymmw2/6/
Update
When I remove text-indent: 100%; from the .breadcrumb__text CSS definition, the .breadcrumb renders as intended. However, when I leave the text-indent in place, and remove the .breadcrumb__text::after definition at the top of the style sheet (as described above), it also renders correctly.
Might this issue have something to do with the either FontAwesome or text-indent and flexbox?
Code
HTML
<body>
<div class="layout_wrapper">
<div class="layout_container__content">
<div class="content">
<header class="content__header">
<div class="breadcrumb">
<span class="breadcrumb__text breadcrumb__text--first">From </span><a class="breadcrumb__link" href="#">Dashboard</a><span class="breadcrumb__text"> to </span><a class="breadcrumb__link" href="#">Find records</a><span class="breadcrumb__text"> to </span>
<h1 class="breadcrumb__current">Kylo Ren’s Command Shuttle™</h1>
</div>
<ul class="page_tools">
<li class="page_tools__item">
<button type="button" class="button button--primary">Save</button>
</li>
<li class="page_tools__item">
<button type="button" class="button">Cancel</button>
</li>
</ul>
</header>
</div>
</div>
<div class="layout_container__sidebar">
<div class="sidebar">
<article class="widget">
<h2 class="widget__title">Widget</h2>
</article>
</div>
</div>
</div>
</body>
CSS
/* Removing this makes it work */
.breadcrumb__text::after {
font-family: "FontAwesome";
font-weight: 400;
}
/* Don't remove anything below */
.breadcrumb__text--first {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
* {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html, body {
padding: 0;
margin: 0;
}
body {
display: flex;
flex-flow: column nowrap;
align-items: stretch;
}
.layout_wrapper {
flex: 1 1 auto;
display: flex;
flex-flow: row nowrap;
align-items: stretch;
}
.layout_container__content {
flex: 0 0 75vw;
}
.layout_container__sidebar {
flex: 0 0 25vw;
}
.content {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: stretch;
}
.content__header {
outline: 1px solid blue;
background-color: #434649;
color: #ffffff;
flex: 0 0 100%;
display: flex;
flex-flow: row nowrap;
}
.breadcrumb {
outline: 3px dashed purple;
flex: 1 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.breadcrumb__text {
flex: 0 0 2em;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
position: relative;
text-align: center;
}
.breadcrumb__text::after {
content: '\f105';
padding: 0;
text-indent: 0;
position: absolute;
top: 0;
right: 0;
width: 100%;
}
.breadcrumb__text--first {
flex: 0 0 0;
}
.breadcrumb__text--first::after {
content: none;
}
.breadcrumb__link {
flex: 0 0 auto;
display: inline-block;
font-size: 0.8571rem;
}
.breadcrumb__current {
flex: 0 0 100%;
margin: 0;
}
.page_tools {
outline: 3px dashed red;
flex: 0 0 auto;
display: flex;
flex-flow: row nowrap;
list-style: none outside none;
}
I just finished reviewing your code and noticed the following:
There are unnecessary (nested) flex containers (caused by using display: flex;).
There are unnecessary flex-related declarations (just declaring the default behavior, such as flex-flow: row no-wrap; and align-items: stretch).
There are several unnecessary declarations in the context of various unrelated selectors. Probably left-over declarations while testing / debugging.
That said, lets continue to your issue. It isn't obvious, so it needs some introduction.
Pangloss introduces an important ingredient of your issue, which affects using text-indent. From W3:
The box is indented with respect to the left (or right, for right-to-left layout) edge of the line box. User agents must render this indentation as blank space.
[...]
If the value of text-indent is either negative or exceeds the width of the block, that first box, described above, can overflow the block. The value of overflow will affect whether such text that overflows the block is visible.
In other words: text-indent affects the dimensions of the box you apply it to.
You have declared overflow: hidden; on .breadcrumb__text. Obviously, for that declaration to have the desired effect, the box you applied it to needs a width, or else it wouldn't have a clipping edge.
.breadcrumb__text should get its width from the flex-basis declaration (specifically flex: 0 0 2em;) applied to it. Well... that's not happening, at least, not entirely as you would expect. Even though its width seems to be 2em, for some reason it doesn't trigger the overflow behavior as it should. This seems to be a bug in the specific Chrome version you use, as its fixed in Canary (eg. version 49 and up).
So: this seems to be an issue with the flexbox implementation in Chrome. That said, with this knowledge, your issue can be fixed in multiple ways. Some examples:
text-indent: -100%
Using text-indent: -100% fixes your issue because it takes away the extra whitespace on the right side of the affected elements. (→ jsfiddle)
width: 2em
You could add the declaration width: 2em to .breadcrumb__text. That would fix the unexpected behavior of the flex-basis declaration. (→ jsfiddle)
overflow: hidden; on parent container
Adding overflow: hidden; on .breadcrumbs fixes your issue. Now the parent container has a clipping edge and handles the whitespace caused by using text-indent: 100%. (→ jsfiddle)
Final remarks
Flexbox is a powerful layout mode and it sure is great to experiment with. But, the algorithms are complex and browser implementations aren't free from issues yet. Make sure you take this into account when using flexbox.
Another concern when looking at your code is the way you use flexbox. Flexbox is there for you to use, but it doesn't necessarily have to replace every other way of dealing with layout. display: inline-block; or display: table;, or even float might do the job without introducing the complexity of nested flex containers.
The FontAwesome typeface isn't the root cause. It's the H1 "block" layout definition set by default in your browser. Add this style to your breadcrumb__current class. See https://jsfiddle.net/44gymmw2/9/
word-wrap:break-word
The H1 tag is a block level element, which will make it push the contents of that block across the entire page. One other fix would be to change that from block to inline, like so:
h1 { display: inline; }
Or you could wrap that text in another element, like a span.
I think the problem is caused by the text-indent:100% rule, that added extra space on the right hand.
The text-indent property specifies how much horizontal space should
be left before the beginning of the first line of the text content of
an element. <percentage> value relative to the containing block
width. -MDN
See this simple demo:
body {
width: 200px;
border: 1px solid red;
}
span {
text-indent: 100%;
display: inline-block;
}
<span>text</span>
In your example, you can just change text-indent:100% to text-indent:-9999px, it works similarly, and it won't create the overflow.
Updated jsfiddle
Try witn inline-block property it is working good.
.content {
display:inline-block;
flex-flow: row wrap;
justify-content: space-between;
align-items: stretch;
}
I have the following HTML:
<div class="outer">
<div class="inner1">Hello</div>
<div class="inner2">World</div>
</div>
With the following CSS:
.outer {
display: flex;
}
.inner1 {
display: flex;
width: 5em;
text-align: right;
}
.inner2 {
display: flex;
width: 5em
}
I would like the text inside the inner1 class to be right justified. I thought the text-align: right would cause this to happen, but it does not.
How can I modify the above HTML and CSS to make the inner1 text, "Hello", be right justified? Why does having display: flex affect this behavior?
You were almost there. You just needed to add the justify-content property.
Add one line of code to your CSS:
.inner1 {
display: flex;
width: 5em;
/* text-align: right; REMOVE; not necessary */
justify-content: flex-end; /* NEW */
}
DEMO: http://jsfiddle.net/5qLdnk5p/1/
Here's a slightly enhanced demo to make the feature more noticeable:
DEMO: http://jsfiddle.net/5qLdnk5p/
From the spec:
justify-content
The justify-content property aligns flex items along the main axis
of the current line of the flex container.
flex-end
Flex items are packed toward the end of the line.
UPDATE
From the comment section:
This is working for me. The only confusion for me is that it says that
justify-content aligns flex-items. Since when is the content (text)
itself considered a flex item? Moreover, is the .inner1 div considered
a flex item, and will the entire div be moved around along the axis
too? – #mareoraft
The inline content in a flex container gets wrapped in an anonymous flex item, which is able to inherit properties from the parent. However, anonymous items (like anonymous block and anonymous inline boxes) are unselectable and therefore unstyleable. So if you want to apply styles to the text consider wrapping it in a <span>, <div> or other element.
The div with class .inner1, as a child of the flex container (.outer), is a flex item. All flex item properties apply. .inner1 also doubles as a (nested) flex container, so all flex container properties apply, as well.
How can I modify the above HTML and CSS to make the inner1 text, "Hello", be right justified?
I know it's a simple example, but check if the following suits your needs:
.wrapper {
border: 1px solid #000;
display: flex;
padding: 2px;
width: 100%;
}
.wrapper > div {
border: 1px solid #000;
flex: 1;
padding: 10px;
}
.left {
text-align: right;
}
.right {
text-align: left;
}
<div class="wrapper">
<div class="left">left (right aligned)</div>
<div class="right">right (left aligned)</div>
</div>
I recommend reading more about the flex property in A Complete Guide to Flexbox
Another method would be setting the following CSS:
Set the text aligning property to: text-align: justify and setting the read direction to: direction:rtl. Other answers are also very good answers.
These adjustments are CSS2 based.
.outer {
display: flex;
}
.inner1 {
display: flex;
width: 5em;
direction:rtl;
text-align:justify;
}
.inner2 {
display: flex;
width: 5em;
}
<div class="outer">
<div class="inner1">Hello</div>
<div class="inner2">World</div>
</div>