Anchor and button elements render differently with same styles - html

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;
}

Related

How do I center these items properly?

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.

Flexbox shrink to content size [duplicate]

In the below example, I have a button with the following styles...
.button-flexbox-approach {
/* other button styles */
display: flex;
justify-content: center;
align-items: center;
padding: 1.5rem 2rem;
}
http://codepen.io/3stacks/pen/JWErZJ
But it automatically scales to 100% instead of the width of the content. You can set an explicit width, but then that doesn't allow your text to wrap naturally.
How can I make a button that has the inner text centered with flexbox, but doesn't grow to fit the size of the container?
.container {
width: 100%;
height: 100%;
}
.button {
/* Simply flexing the button makes it grow to the size of the container... How do we make it only the size of the content inside it? */
display: flex;
justify-content: center;
align-items: center;
-webkit-appearance: none;
border-radius: 0;
border-style: solid;
border-width: 0;
cursor: pointer;
font-weight: normal;
line-height: normal;
margin: 0;
position: relative;
text-align: center;
text-decoration: none;
padding: 1rem 2rem 1.0625rem 2rem;
font-size: 1rem;
background-color: #D60C8B;
border-color: #ab0a6f;
color: #fff;
}
.one {
margin-bottom: 1rem;
}
.two {
/* You can put an explicit width on that, but then you lose the flexibility with the content inside */
width: 250px;
}
<div class="container">
<p>
Button one is flexed with no width and it grows to the size of its container
</p>
<p>
<a class="button one" href="#">Button</a>
</p>
<p>
Button two is flexed with an explicit width which makes it smaller, but we have no flexibility for changing the content
</p>
<p>
<a class="button two" href="#">Button 2</a>
</p>
</div>
Instead of display: flex on the container, use display: inline-flex.
This switches the container from block-level (which takes the full width of its parent) to inline-level (which takes the width of its content).
This sizing behavior is similar to display: block vs. display: inline-block.
For a related problem and solution see:
Make flex items take content width, not width of parent container
EDIT: Michael_B pointed out in his answer that inline-flex on the parent is the correct property for this use-case. I've updated my blog post accordingly.
It's not ideal, but if you wrap the button in a container that is inline-block, the button will scale naturally with the content, like so:
.button {
/* other button styles */
display: flex;
justify-content: center;
align-items: center;
padding: 1.5rem 2rem;
}
<div style="display: inline-block;">
<a class="button">Button</a>
</div>
You can then set the max-width on the container and the text will wrap to multiple lines, but retain the correct vertical centering.

Flexbox sizing doesn't work correctly when using FontAwesome

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;
}

Align icon vertically to the center of the first line of text

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

How do I get the background color only behind the text?

This is my code but I want the text to only have background color behind it, and not stretch across the entire screen? Any ideas?
.section_title {
background-color: orange;
text-align: center;
margin: 0px auto;
}
HTML is
<div class="col-md-12">
<div class="section_title">
<h2>Choose a Pack to Print</h2>
</div>
</div>
An option is adding display: inline-block; to the CSS of the text element.
One problem I found with display: inline-block; is it clears floats incorrectly. Instead, I use width: fit-content;
.highlight {
background: yellow;
padding: 0.5em;
width: fit-content;
}
<h1 class="highlight">Highlight for text only!</h1>
<h1 class="highlight">Highlight me too!</h1>
There's a few ways to do this, but probably the best way is to make the h2 inline or inline-block.
Using inline-block will allow you to set width/height.
.section-title {
text-align: center;
}
.section-title h2 {
display: inline-block;
}
The other way to do this is to set a width on the h2 and set the margin to auto;
.section-title h2 {
margin-left: auto;
margin-right: auto;
width: 50%; /* for example */
}
If you want all your headings to be a set width, I'd choose the second one (allowing for text to wrap). If you want the box to be flexible and hug the contents, I'd use the first.