Here are the eyes with align-items: center property. They are OK for one-line text and FAIL for multiline text:
Here are the eyes with align-items: baseline (or flex-start). They are better for multiline text but not ideal for all of them because I want to align the eye to the center of first line of the text:
What I’m trying to achieve is this:
See how the eye image is centered at the first line of the text?
Is it possible to do it elegantly with flexbox properties, without using padding or margin?
(This is a simplified example. In the real problem I don’t want to introduce padding because it will affect other items.)
Here is jsfiddle to play with: http://jsfiddle.net/sqp1wdap/
I found the solution: http://jsfiddle.net/sqp1wdap/3/
Align both Eye and Text to flex-start
Make line-height for text same as Eye height
Here is the edited code:
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: flex-start; // ← edit (1)
background: #eee;
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
align-self: flex-start; // ← edit (1)
background: #eaa;
line-height: $fontSize; // ← edit (2)
}
And here is how it looks like:
Of course, if the icon height equals the line height it will be 'aligned' to the first line.
Normally, those two things will be different. You can't actually change the line height or the icon height without impacting the visual design.
So the solution for this would be to wrap the icon with a flex container which height equals the text line-height. This container will do the vertical centering of the icon. If the icon is larger than the container then it will just overflow from top and bottom.
So in your example (I'm just exaggerating the height for clarity, you could also try with very smalls values, like 8px and see how it works in both scenarios)
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #eee;
height: 100px; /* <-- set this */
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
background: #eaa;
line-height: 100px; /* <-- equal to this, no need to set this, just use right value above */
}
Notice that you don't actually need to change the text line-height, just set the eye container height to whatever that value should be.
Fiddle working for cases in which line-height is bigger than icon: http://jsfiddle.net/ofdwemva/
Fiddle working for cases in which line-height is smaller than icon: http://jsfiddle.net/ofdwemva/1/
I found the solution without altering line-height property of the text.
Same like oluckyman's answer before, align both Eye and Text to flex-start.
Add hidden pseudo-element on Eye which resembles the height of the Text.
Use center alignment for the Eye which will aligns the Eye itself and the pseudo-element we've created.
Here is a link to JSFiddle and summary of what I did:
.LegendItem {
min-height: $itemHeight;
font-size: $fontSize;
margin: 2px 0;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: flex-start; // <-- Change this
}
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #bbb;
}
.LegendItem_Eye::before { // <-- Add this
content: "A";
width: 0px;
visibility: hidden;
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
background: #eaa; // <-- Remove align-self
}
And it will look like this.
A lot of the answers here are going to be depending on your situation - the current (and wrongly) accepted answer would only work if your designer does not mind that you butcher the line height which is no good for most.
If you want to do this ultimately your goal is to get the icons container to be the same height as one line of text and then align the icon within this container to be centered.
A decent method of doing this is by duplicating a bit of text with the same css as the text you want to be centered against then hiding it, This will ensure that the container is now the same height as the text. Now you simply center align the icon.
Heres an example in react (the css is the same)
export function CheckmarkListItem({ point }: Iprops) {
return (
<Div>
<IconContainer>
<SvgWrap size={20} mixin={svgMix}>
<Checkmark />
</SvgWrap>
<HiddenDiv>
<Typo tag="p">Mock text</Typo>
</HiddenDiv>
</IconContainer>
<PointDiv>
<Typo tag="p">{point}</Typo>
</PointDiv>
</Div>
);
}
const Div = styled.div`
display: flex;
text-align: left;
gap: 15px;
${(props) => props.theme.breakpoints.up.md} {
gap: 30px;
}
align-items: flex-start;
`;
const PointDiv = styled.div``;
const IconContainer = styled.div`
display: flex;
align-items: center;
`;
const svgMix = css`
margin: 0;
`;
const HiddenDiv = styled.div`
visibility: hidden;
width: 0;
`;
.LegendItem_Eye {
width: $slotWidth; // keep width
float:left; // float left
line-height:1.3; // define line height
}
That should be all you need. Demo.
I am not sure whether there is an elegant way to do it with flex but i can provide you a crack for the same and that will not affect any-other elements as far as i guess:
you can add custom styling for font-awesome.css
.fa{
position: absolute;
top: 0;
left: 0;
text-align:center;
padding:3px;
}
And for your custom style you can do this:
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #eee;
position: relative; /* Added this new rule */
}
I know this is not the proper solution but you can give this a try unless it harms other elements. :)
jSFiddle
Related
As title says-
I'm setting anchor and button to flex but their sizes are different.
Why does this happen? How can I achieve same visual on both elements with auto width?
a,
button {
display: flex;
align-items: center;
justify-content: center;
width: auto;
background: orange;
margin-bottom: 20px;
padding: 10px;
height: 50px;
margin: 0;
}
asdf
<button>asdf</button>
Here, in `width:auto`, auto tells the default value. The browser calculates the width.
Also both are different elements.
div {
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
}
a,
button {
width: auto;
background: orange;
padding: 30px;
margin: 0;
}
a {
padding-bottom:31px;
}
<div>
asdf
<button>asdf</button>
</div>
My problem consists of 2 parts:
button and a render differently
I wanted a to render like button in this example. So the component I'm designing will not make its users to wrap it and so on and so forth.
The correct answer is arround width property set to fit-content. It has pretty good browser support and I'll try to use it.
Thanks a lot for your answers!
This depends on the engine but the most probable cause of this in browsers is due to the box-sizing property of css. MDN defines box sizing as
By default in the CSS box model, the width and height you assign to an
element is applied only to the element's content box. If the element
has any border or padding, this is then added to the width and height
to arrive at the size of the box that's rendered on the screen. This
means that when you set width and height, you have to adjust the value
you give to allow for any border or padding that may be added. For
example, if you have four boxes with width: 25%;, if any has left or
right padding or a left or right border, they will not by default fit
on one line within the constraints of the parent container.
You can read more about this here: https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing how using
But the closest you can reach is by using width as inherit. This will cause the elements to inherit width from parent.
// Resetting both to have same type for similar render
a,button {
box-sizing: content-box;
border: unset;
}
a,
button {
display: flex;
align-items: center;
justify-content: center;
background: orange;
margin-bottom: 20px;
padding: 10px;
height: 50px;
margin: 0;
}
// Add width to parent element
.w-100 {
width: 100vw;
}
// This will cause the default width behaviour to inherit from parent
a,button {
width: inherit;
}
<div class="w-100">
asdf
<button>asdf</button>
</div>
This problem arises from button not being allowed to have some of the other display properties depending on the engine. Wrapping button in a span is the easiest solution.
asdf
<span><button>asdf</button></span>
a, span {
display: flex;
align-items: center;
justify-content: center;
width: auto;
background: orange;
margin-bottom: 20px;
padding: 10px;
height: 50px;
margin: 0;
}
I have the code here but basically the problem is I have these product cards and I am trying to get them in the center but also align them with the other cards if that makes sense.
https://codepen.io/manfreebie/pen/NWNvyGz
Here is a visual of what I want to accomplish vs. what is actually happening. It looks fine at first till you try to resize it.
I have tried to make the cocktail-container have the value flex-start instead of center for the justify-content attribute like this
#cocktails-container {
max-width: 70%;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
but that leaves a lot of whitespace on the right side when I resize it. I have tried playing around a little bit with inline-block and using text-align instead but that didn't work either.
Add this code.
#cocktails-container::after {
content: "";
flex: auto;
}
I am only sharing parts that I changed, the rest is the same.
#cocktails-container {
width: 70%; // You can adjust this for your needs
display: flex;
flex-flow: row wrap;
justify-content: start;
}
// Removed margin from .cocktail but added padding to the a tag
.cocktail {
width: 100%;
height: auto;
padding-top: 10px;
text-align: center;
}
a {
width: 33%; // You should adjust this for different screen widths, mobile 100% large 25% etc.
padding: 15px;
box-sizing: border-box; // This is necessary to include padding in '33% width'
}
Please try this code,To How do I center these items properly?
.box {
display: flex;
align-items: flex-start;
height: 200px;
}
.box .selected {
align-self: center;
}
<div class="box">
<div class="selected">Three</div>
</div>
I hope this code will be useful for you.
Thank you.
The issue that I identified while checking the code is that you are using a margin margin: 50px 0px; for the .cocktail class. Change it to the below one.
#media (max-width: 800px) {
.cocktail {
width: 60%;
margin: 50px auto;
}
}
Giving margin value 50px 0px; will make the left and right margin to zero in the samller resolution. Update that to 50px auto that will give left and right margins auto value.
I have a code - https://codepen.io/anon/pen/MQjpBG
It's a simple list with a colored block and text in each li
I need the list to be vertical and the text and block to be vertically aligned.
I'm trying to do this with flex and align-items but the text and block never center exactly
Am I doing something wrong, is there a better way to do this.
.element{
display: flex;
list-style: none;
&__item{
display: flex;
align-items: center;
margin-right: 10px;
&:last-of-type{
margin-right: 0;
}
&-square{
background: red;
//display: block;
display: inline-block;
height: 20px;
width: 20px;
}
&-text{
font-weight: bold;
}
}
}
I want the block and text to fit like so.
The align-items: center; seems to do it but its slightly off, like
There's nothing centering them (in your codepen).
Add this to your code:
.element{
display: flex;
justify-content: center; /* horizontal alignment */
.element__item {
display: flex; /* nested flex container */
align-items: center; /* vertical alignment */
}
revised codepen
Unfortunately, it looks like the issue is a function of the font chosen. Different fonts will have different descender heights (e.g. the tail of a "g") as well as different positioning of the base line relative to the full text box, and it appears that some fonts will have these values set such that they may not be visually centered.
I modified your CodePen example and forcibly set the font-family of the first element to Arial while leaving the second as the default (on Firefox on macOS 10.15/Catalina), and the Arial version definitely looks much more vertically centered:
You may be able to fix this by changing the font used, but obviously this isn't a change that can be made lightly on a large codebase.
To make the list to be vertical, just add "flex-direction"
display: flex;
list-style: none;
flex-direction: column;
For horizontally center aligned:
.element {
justify-content: center;
}
For vertical center alignment of squares and text:
.element__item-square {
vertical-align: middle;
}
.element__item-text {
vertical-align: middle;
}
I have been searching around, but for the life of me I cannot figure out what's going on. My text is getting wrapped at certain tags, while I want it all on one line.
I have aligned three DIV elements next to each other through the use of display: flex;
This all works out quite nicely and display is exactly the way I want it. Except for the fact that, for some unexplicable reason (at least to me), if I put a text snippet in one of those divs and that text snippet contains something between tags like <span></span> or <b></b>, the text is automatically wrapped before and after the tag onto a new line.
I have the code here:
.pagetitlewrapper {
width: 99%;
background-color: #c1dbff;
border-radius: 25px 25px 0px 0px;
padding: 10px;
display: flex;
text-align: center;
}
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
align-items: stretch;
display: flex;
justify-content: center;
flex-direction: column;
}
.pagetitleleft {
text-align: left;
font-size: 9;
}
.pagetitlecenter {
text-align: center;
}
.pagetitleright {
text-align: right;
font-size: 9;
resize: vertical;
}
<div class='pagetitlewrapper'>
<div class='pagetitleleft'>Welkom, FNAME LNAME</div>
<div class='pagetitlecenter'><h1>Nexus Consult DMS</h1></div>
<div class='pagetitleright'>
Licensed to <span>DON'T WRAP</span> - License valid until xx/xx/xxxx.
</div>
</div>
Around the DON'T WRAP, I have put <span> tags to illustrate the problem. If you remove these tags, the text is all displayed on one line as I want it. Basically I want to be able to make DON'T WRAP bold without it wrapping the text before and after.
I have been searching the web, to no avail. I found a couple of code snippets online which surprisingly did the same thing. I wonder why nobody ran into this problem before?
I have tried to play a bit with white-space: nowrap; in CSS, but that didn't seem to work either.
Anyone has any idea? Someone can point me in the right direction?
Thanks,
Kenneth
Why it break line is because of the display: flex; flex-direction: column on the pagetitleleft/center/right elements, which make the span a flex column item and take 100% width.
By dropping the display: flex on the pagetitleleft/center/right elements and set align-items: center to their parent, their text will center vertically
.pagetitlewrapper {
width: 99%;
background-color: #c1dbff;
border-radius: 25px 25px 0px 0px;
padding: 10px;
display: flex;
align-items: center;
}
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
}
.pagetitleleft {
text-align: left;
font-size: 9;
}
.pagetitlecenter {
text-align: center;
}
.pagetitleright {
text-align: right;
font-size: 9;
resize: vertical;
}
<div class='pagetitlewrapper'>
<div class='pagetitleleft'>Welkom, FNAME LNAME</div>
<div class='pagetitlecenter'><h1>Nexus Consult DMS</h1></div>
<div class='pagetitleright'>
Licensed to <span>DON'T WRAP</span> - License valid until xx/xx/xxxx.
</div>
</div>
This behavior makes sense and is defined in the flexbox specification.
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each
contiguous run of text that is directly contained inside a flex
container is wrapped in an anonymous flex item.
Your right column (.pagetitleright) is a flex container with flex-direction: column:
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
align-items: stretch;
display: flex;
justify-content: center;
flex-direction: column;
}
In this container, you have three flex items:
<anonymous-flex-item>Licensed to</anonymous-flex-item>
<span>Licensed to</span>
<anonymous-flex-item>- License valid until xx/xx/xxxx.</anonymous-flex-item>
As a result, you're getting three flex items stacked vertically.
It doesn't matter if you use span, b, strong, em. Whatever elements you create in the container become flex items and behave accordingly.
If you don't want these elements to stack vertically, then don't use flex-direction: column.
There is a simple solution. just add white-space: pre-wrap;
Some-Flex-Container {
display: flex;
white-space: pre-wrap; /* solution */
}
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;
}