Merging width and flex properties for utility classes - html

On my site, I have a lot of utility classes that sets the width of elements. For almost all of the cases, the width property is perfect. The only issue is with flex box. For flex items, the width property does not set the width, and instead the flex property needs to be used. I tried combining the two into a single class like so:
.width-100 {
width: 100px !important;
flex: 0 0 100px !important;
}
Surprisingly enough, this worked on the few places I tried it. When an element is not using flexbox, its width gets set properly. When an element is using flexbox, the flex property makes sure it works as well. However, I am wondering if this is a good idea or not. Could there be possible bugs that I am simply not foreseeing right now?

You may fall into the case where you have min-width constraint and setting the width will make the flex item behave differently:
Here is a basic example:
.container {
display:flex;
margin:5px;
}
.container > img {
flex: 0 0 100px;
}
.container > span {
flex-grow:1;
background:red;
}
<div class="container">
<img src="https://i.picsum.photos/id/100/200/100.jpg">
<span></span>
</div>
<div class="container">
<img src="https://i.picsum.photos/id/100/200/100.jpg" style="width:100px">
<span></span>
</div>
In the first case the min-width constraint of the image will force it to have a width equal to 200px whereas in the second case you will have 100px. So it's wrong to assume that width isn't working in flexbox and you need flex-basis.Your code will indeed force the width to always be 100px but it's not the same as flex:0 0 100px when dealing with flex items:
By the way, your code can be simplified to only
.width-100 {
width: 100px !important;
flex-shrink: 0 !important;
}
This should produce the same output because flex-grow is by default 0 and flex-basis will consider the width you set.

Related

CSS specificty issue

I have a nested div like this
<div class="myDiv">
<div class="myOtherDiv">
In my CSS I want myOtherDiv to have margin: 0 auto; but not myDiv
If I write
.myDiv{
margin: 0 auto;
}
It applies to both with the specificty of 0,1,0
But
.myDiv .myOtherDiv{
margin:0 auto;
}
Nothing happens. Which is weird, visual code reports the specificity of this to be 0,2,0 which is higher so should it not apply?
As you have not provided all of the CSS code it is hard to tell. However,
Issues with margin: 0 auto;
are you usually a result of the element not being a block element or contain a width.
Since div is a block element naturally, it takes up the entire width available even if you only have 1 letter inside that div(I.e <div>A</div>
You must declare a width before centering your div items.
So for example:
.myDiv {
width: 50%;
margin: 0 auto;
}
Im regards to specificity,
If the parent <div> doesn't have a width assigned margin:0 autowill not do anything. However, if you assign a width then the block will not occupy all the page's space, and then the block itself is centered, but the items of the child div will not be centered or affected.
If you assign both the child and parent div margin:0 auto without either having a set width it will produce a null effect without affecting positioning at all because each block is just taking up all the space possible within the page.
If you want the child div block centered, then assign a width to the child div, and leave the parent div alone. Since the parent occupies all the page's width space, the child div will be centered on the page using margin:0 auto; and the width you assigned.
.myDiv .myOtherDiv {} or just .myOtherDiv {} should be good to target myOtherDiv.
Did you give the div a width? Block level elements like div's default to 100% widht of their parent. So you need to set a specific smaller width, or use display: table; so the content decides the width. See below:
.myDiv{
background: blue;
}
.myOtherDiv{
margin: 0 auto;
display: table;
background: red;
}
<div class="myDiv">
<div class="myOtherDiv">content
</div>
</div>

inline flex container width not growing

Consider the following layout:
<div class="div">
<span class="span1">test</span>
<span class="span2">test test test test test</span>
</div>
and the css:
.div{
display:inline-flex;
background-color:lightgray;
}
.span1{
flex:0 0 100px;
}
.span2{
white-space:nowrap;
}
Why isn't the div stretched wide enough to cover the two spans? This happens in FF and Chrome. In IE 11/Edge it works (as I would expect it to work)
Here's the fiddle https://jsfiddle.net/p18h0jxt/
PS: It works everywhere if I used the following style:
.span1{
flex:0 0 auto;
width:100px;
}
Thanks.
From this SO answer:
Bug affecting all major browsers, except IE 11 & Edge:
Just as you said - apparently flex-basis is not respected in a nested flex container.
So your 100px flex-basis from flex: 0 0 100px; can't work properly (except ironically in IE 11 & Edge).
The workaround (also mentioned here) is to use width instead of flex-basis like so:
.div {
display: inline-flex;
background-color: lightgray;
}
.span1 {
width: 100px;
}
.span2 {
white-space: nowrap;
}
<div class="div">
<span class="span1">test</span>
<span class="span2">test test test test test</span>
</div>
You could use flex instead of inline-flex, but then your div will be rendered like a block element i.e. it will take up the full width that's available rather than being confined to your content.
I assume you are using inline-flex so that the background remains confined to the content.
The 100px you refer to in your current example refers to flex-basis not the element width.

creating equal width flex items

I'm using flex for layout purposes, but the browser does not spread the width equally between items.
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1 1 auto;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
Now, I want the buttons to split the container length 50% / 50%.
But that's not what's happening. I tried using flex: 1 1 auto and flex: 1 1 0 but with no success.
I know that I can use the OK button directly and it will solve my problem, but in my particular scenario it's important to wrap it with a div.
Now, as I understand it, flex should be able to spread the width equally and that's my goal here.
One more thing though, I noticed that the button content seems to have an effect on the width and I want to ignore this effect somehow.
Thanks!
JSFiddle example:
https://jsfiddle.net/edismutko/cvytLkyp/3/
flex-basis: auto vs flex-basis: 0
You're sizing your flex items with flex: 1 1 auto.
However, if you want to distribute space evenly among items, you need to use flex: 1 1 0.
The difference is the flex-basis component.
With flex-basis: 0, every item is considered to have a zero width and flex-grow distributes container space equally among them. This results in all items having the same length.
With flex-basis: auto, the size of the item is factored into the flex-grow calculation and container space is distributed proportionally among items.
So when you want equal length items use flex: 1 1 0, which is the same as flex: 1.
Here's a more detailed explanation: Make flex-grow expand items based on their original size
Default rules on button elements
Browsers apply styles to elements by default. For instance, Chrome adds padding and border widths to button elements.
Reset those defaults.
Now you have two equal width flex items. (Additional styling is up to you.)
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1;
}
button {
padding: 1px 0;
border-left-width: 0;
border-right-width: 0;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
box-sizing: border-box
Something else to consider is including the padding and border lengths in the width / flex-basis calculation. Why are borders causing div to overflow container?

Inline-block box model vs. Block box model on layout elements?

Let's see this piece of code :)
HTML
<div class="mid">
test inline-block
</div>
<div class="mid">
test inline-block
</div>
<div class="floated">
test block floated
</div>
<div class="floated">
test block floated
</div>
CSS
.mid {
display: inline-block;
margin: 0;
padding: 1em;
box-sizing: border-box;
width: 47.5%;
background: red;
}
.mid + .mid {
margin-left: 4%;
}
.floated {
float: left;
display: block;
background: green;
margin: 0;
padding: 1em;
box-sizing: border-box;
width: 47.5%;
}
.floated + .floated {
margin-left: 5%;
}
You can also see the fiddle for testing purpose : http://jsfiddle.net/LdDSJ/
Now my question : on normal size, both inline-block and floated block are side-by-side, it's ok. But note they are not equal in width.
Try to resize the window : the inline-block elements breaks, one going below the other. By the way, I had to put a lower margin-left to that element because it would have break.
I know there's some whitespace around there, so my question is : is it viable to put layout elements display: inline-block instead of display:block + float property ? As all solution provided (How to remove the space between inline-block elements?) seems hacky (font-size:0, using comments, ...) ?
The CSS property display:inline-block; involves a white-space between elements. The size of this spaces depends on browser. So your calculation :
47.5% + 47.5% + 5% (margin-left) != 100%
Isn't correct because it doesn't include that white-space.
There are many ways to remove that white-space, you can find some here
Edit : to make it very simple ( this can't work in all cases but it can help you choose)
If your question is should I use display:inline-block; (otpion 1) or display:block with float property (option 2), my answer will be it depends on your aim.
Both solutions can need work arounds.
Case 1
You need your elements to expand the total width of container.
Use use option 1 so no work around is needed.
Case 2
You need your parent element to expand it's height according to children.
Use display:inline-block;
Case 3
You need both (parent's height expand according to children and total width of elements = 100%)
Then you will need work around with both options. For option 1 see here for option 2 you will need to clearfix or float parent container.

CSS alternative to center

People frown upon the center tag, but for me it always works just the way I want it. Nevertheless, center is deprecated so I'll make an effort.
Now I see many people suggest the cryptic CSS margin: 0 auto; but I can't even get it to work (see fiddle here). Other people will go modify position or display, but that always breaks something else.
How can I center a span using css so that it behaves exactly like the center tag?
<div class="container">
<span class='btn btn-primary'>Click me!</span>
</div>
Span is an inline element, and the margin: 0 auto for centering only works on non-inline elements that have a width that is less than 100%.
One option is to set an alignment on the container, though this probably isn't what you want for this situation:
div.container { text-align: center }
http://jsfiddle.net/MgcDU/1270/
The other option is to change the display property of the span:
/* needs some extra specificity here to avoid the display being overwritten */
span.btn.btn-primary {
display: table;
margin: 0 auto;
}
Using display: table eliminates the need to hard code a specific width. It will shrink or grow as appropriate for its content.
http://jsfiddle.net/MgcDU/1271/
You can set .container { text-align:center; } so that everything inside div.container will be centered.
In general, there are two ways centering things.
To center inline elements (such as text, spans and images) inside their parents, set text-align: center; on the parent.
To center a block level element (such as header, div or paragraph), it must first have a specified width (width: 50%; for example). Then set the left and right margins to auto. Your example of margin: 0 auto; says that the top and bottom margin should be 0 (this doesn't matter for centering) ad that the left and right margins should be auto - they should be equal to each other.
The <center> element is really just a block-level element with text-align:center;. If you sent border: solid red 1px; on it, you can see that it's 100% wide, and that everything inside it is centered. If you change text-align to left, then its children are no longer centered. Example: http://jsfiddle.net/KatieK/MgcDU/1275/. Perhaps you should just consider your <div class="container"> with text-align:center; } to be equivalent to <center>.
You make the span block level, give it a width so margin:auto works
see this fiddle
.center {
display:block;
margin:auto auto;
width:150px; //all rules upto here are important the rest are styling
border:1px solid black;
padding:5px;
text-align:center;
}
UPDATE: In order to NOT specify a width and have natural width of element on the span you will have to use textalign on parent
see this fiddle
.container{text-align:center}
.center {
border:1px solid black;
padding:5px;
}
<span> is an inline element. <div> is a block element. That's why it is not centering.
<div class="container" style='float:left; width:100%; text-align:center;'>
<span class='btn btn-primary'>Click me!</span>
</div>
You can center the content of span only when you convert it into block, using 'inline-block' style.
Your parent element needs to have a larger width in order to let a child element be positioned within it. After that the trick with margin: 0 auto; is getting the parent and child container position and display values to be compatible with each other.
.container {
border: 2px dashed;
width: 100%;}
.btn {
display: block;
margin: 0 auto;
width: 25%;
}
http://jsfiddle.net/rgY4D/2/