Non-wrapping CSS Flex with fixed widths - css

I'm building a Carousel-type component, but am having some difficulty getting it to work just right.
My basic approach is a div (wrapper) with lots of other divs (items) in it. I want to display 4 items on the carousel at any one time. The items have various content heights, but the heights of the items should be equal (to the largest required).
I can't work out the CSS combination I need to get this to work correctly.
With this setup (HTML + CSS at bottom of post), the width: 25%; on each item-container is ignored.
If I add a fixed with to .item, then the 25% kicks in, but the item width is unknown -- it depends on the browsers size. Setting it to 1000px means you lose content from the item. Setting it to ~210px works, but when you start shrinking your browser, you lose content. On a large browser, you have excessive spacing.
Curiously, if I add flex-wrap: wrap to the CSS, then the 25% width is applied correctly -- but I can't do that, because then it's not a carousel! Example
The scenario is simple:
An unknown amount of items in a div with overflow: auto, which are equal heights should be displayed, with 4 of the children divs on the screen at any one time.
My HTML is structured as follows:
<div id="container">
<div id="wrapper">
<div class="item-container">
<div class="item">
<p>
Carousel Item #1 with some quite long text.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #2.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #3.
</p>
</div>
</div>
...
</div>
</div>
My CSS:
#container {
width: 100%;
background: #0f0;
overflow: auto;
}
#wrapper {
display: flex;
}
.item-container {
border: 1px solid #f00;
width: 25%;
}
Note, this is my MCVE. On my real component, I have buttons for scrolling left and right, the content is significantly more complex and stuff like that.

All you need is to add flex: 0 0 auto to .item-container elements.
* {
box-sizing: border-box;
}
#container {
width: 100%;
background: #0f0;
overflow: auto;
}
#wrapper {
display: flex;
}
.item-container {
border: 1px solid #f00;
flex: 0 0 auto;
width: 25%;
}
<div id="container">
<div id="wrapper">
<div class="item-container">
<div class="item">
<p>
Carousel Item #1 with some quite long text.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #2.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #3.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #4.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #5.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #6.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #7.
</p>
</div>
</div>
</div>
</div>

Related

How align several texts and images without flex

There are several subjects on StackOverFlow as here, but the answers are not intuitive for a beginner.
How to align several text and images in CSS
How to align several text and images in CSS
Actually, I would like to center 2 images on the same line, in bottom of each image there are a title and a subtitle. I would like to make it without display: flex.
I don't understand why the seconde image is not aligned horizontally correctly?
.row{
padding-top: 15px;
text-align: center;
}
.imgP{
background-color:red;
margin: auto 5px;
}
<body>
<div class="row">
<img class="imgP" src="https://zupimages.net/up/21/18/te8n.png" alt="image">
<div class="title">My title</div>
<div class="subtitle">Subtitle</div>
<img class="imgP" src="https://zupimages.net/up/21/18/te8n.png" alt="image">
<div class="title">My title</div>
<div class="subtitle">Subtitle</div>
</div>
</body>
Flex is the easy and modern way to do it. If you don't want to use flex, use display:inline-block. For that, you need to create 2 column divs and wrap the content inside it.
.row {
padding-top: 15px;
text-align: center;
}
.col {
display: inline-block;
}
.imgP {
background-color: red;
margin: auto 5px;
}
<body>
<div class="row">
<div class="col">
<img class="imgP" src="https://zupimages.net/up/21/18/te8n.png" alt="image">
<div class="title">My title</div>
<div class="subtitle">Subtitle</div>
</div>
<div class="col">
<img class="imgP" src="https://zupimages.net/up/21/18/te8n.png" alt="image">
<div class="title">My title</div>
<div class="subtitle">Subtitle</div>
</div>
</div>
</body>

Setting wrapper div to position absolute shrinks wrapper to arbitrary width

I'm running into an issue with position: absolute and I can't find an answer anywhere that explains why it's happening.
I have a flexbox container inside a wrapper with two children that are each set to flex-basis: 50%. When I set position: absolute on the wrapper div, the wrapper shrinks in an unpredictable way.
See the code below:
.outer-wrapper {
position: relative;
width: 100%;
}
.outer-wrapper .wrapper {
position: absolute;
}
.outer-wrapper .wrapper .flex-container {
display: flex;
}
.outer-wrapper .wrapper .flex-container .flex-item {
flex-basis: 50%;
}
<div class="outer-wrapper">
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
</div>
Removing line 6 in the CSS causes the flex-container to expand to the full width of the parent and each flex child takes up 50% of the width, as expected. However, when I set the wrapper div to position: absolute, the wrapper div shrinks to what seems like an arbitrary width and the text in the flex-children breaks onto multiple lines.
My questions:
Why does setting position: absolute on the wrapper div cause the wrapper div to shrink smaller than its content?
How does the browser determine what width to shrink the wrapper div to? It seems to me like it would either shrink to be as small as possible without introducing line breaks into the text, or would shrink as small as possible while still fitting the longest word, but instead it's shrinking to somewhere in the middle (it only introduces one line break in a string of short words).
Is there a way, while still using flexbox and position: absolute in this way, to force the browser to not shrink the wrapper smaller than its content (unless there is a max-width set on the wrapper)?
Really appreciate any help! This has been driving me crazy!
Why does setting position: absolute on the wrapper div cause the wrapper div to shrink smaller than its content?
How does the browser determine what width to shrink the wrapper div to?
The trick is the use of flex-basis::50%. You are in a situation where you are using a shrink-to-fit container (position:absolute element) and at the same time you are using percentage value inside the flex-basis. So the browser is first calculating the width of the container (ignoring the flex-basis) then the width calculated will be used as reference for the flex-basis.
Here is an illustration of what is happening:
.wrapper {
position: absolute;
border:1px solid red;
}
.wrapper .flex-container {
display: flex;
}
.wrapper .flex-container .flex-item {
/*flex-basis: 50%;*/
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
<div class="wrapper" style="top:100px;">
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text That Is Long
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
</div>
Notice how in the first example (without flex-basis) the width is equal to the largest content. In the second example you will see that the total width didn't change but we made the flex items equal in width.
The same logic also happen with inline-block or float or any shrink-to-fit container.
.wrapper {
display:inline-block;
border:1px solid red;
}
.wrapper .flex-container {
display: flex;
}
.wrapper .flex-container .flex-item {
/*flex-basis: 50%;*/
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
<br><br>
<div class="wrapper">
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text That Is Long
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
</div>
To get what you want it's clear that you need to not use flex-basis:50% and consider a different idea to get the same width.
Here is one using CSS grid as I think it would be tedious with flexbox:
.wrapper {
position:absolute;
border:1px solid red;
}
.wrapper .flex-container {
display: grid;
grid-template-columns:repeat(2,1fr);
}
.wrapper .flex-container .flex-item {
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
The reason it is shrinking is since you are setting position absolute without specifying a width.
Block element feature of having the full width of the parent's content area will not be honored when an element is absolute positioned.
If you want to retain the width (100% of the container) of a block element, then set the width of the absolute element .wrapper to 100% and problem solved.
.outer-wrapper {
position: relative;
width: 100%;
}
.wrapper {
position: absolute;
width:100%;
}
.flex-container {
display: flex;
}
.flex-item {
flex-basis: 50%;
}

Center elements vertically in Bulma

I just started setting up my blog prototype with Bulma. There is a footer section with two equally divided columns.
I'd like the three items (Twitter, Email, etc.) to be vertically centered in the yellow area. Is there any special class for that available in Bulma?
(Please see the full example on codepen.io.)
<footer class="footer" style="background-color: lightpink;">
<div class="columns">
<div class="column has-text-centered-touch" style="background-color: cyan;">
<p>Some copyright stuff...</p>
<p>Templated with Bulma. Published with Hugo.</p>
</div>
<div class="column has-text-right" style="background-color: yellow;">
<div class="level">
<div class="level-left"></div>
<div class="level-right">
<a class="level-item" href="#">Twitter Icon</a>
<a class="level-item" href="#">Email Icon</a>
<a class="level-item" href="#">LinkedIn Icon</a>
</div>
</div>
</div>
</div>
</footer>
You could add the following CSS so the right side column so it is vertically centered.
https://codepen.io/anon/pen/XzmEgr
.footer .has-text-right {
display: flex;
justify-content: center;
}
Make the height of the .level on the right side 100%
.right-side > .level {
height: 100%;
}
JSFiddle

Angular 2 material and flex-layout alignment

I am trying to use angular 2 material and flex-layout to create a responsive gallery of elements. After hours and hours, I still can't have my elements centered:
This is the source code:
<div fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
<md-card fxFlex.gt-md="20" fxFlex.md="28" fxFlex.sm="40" fxFlex.xs="100" *ngFor="let recipe of recipes" [routerLink]="['/details', recipe.id]" class="recipe-card">
<md-card-header>
<md-card-title>element</md-card-title>
</md-card-header>
<img md-card-image src="http://placehold.it/350x200">
<md-card-content>
<p>
Lorem Ipsum
</p>
</md-card-content>
</md-card>
</div>
I have tried different values for fxFlexAlign (https://github.com/angular/flex-layout/wiki/API-Documentation) but none of them achieves what I need, that is, having the elements centered or, in other words, distribute the red square space between the right and the left side.
Is there a way of achieving this?
EDIT
Unfortunately, justify-content: space-between; doesn't work if I have a dynamic number of items. Eventually, they will be wrapped in a new line, and then the item in the last row won't look as expected:
.container {
display:flex;
width:100%;
flex-flow:row wrap;
justify-content: space-between;
}
.block {
width:100px;
height:100px;
border:1px solid red;
}
<div class="container">
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
<div class="block" fxLayout='row' fxLayoutWrap fxLayoutGap="2rem">
... you content
</div>
</div>
<div fxLayout="row" fxLayoutWrap fxLayoutGap="2rem" fxLayoutAlign="center">
Adding fxLayoutAlign="center" worked out for me, the results are now positioned in center.
You can try this concept to acheive a similar functionality. You may have to edit css % values to get more perfect results.
.sp{
display: flex;
justify-content: center;
}
.i{
width: 23%;
height: 133px;
background-color: grey;
margin: 3px;
color: #fff;
}
.p{
display: flex;
flex-wrap: wrap;
width: 56%;
}
<div class="sp">
<div class="p">
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
<div class="i"> content </div>
</div>
</div>
Late to answer but its work on dynamic item, i can't find the exact formula
my formula is
margin-bottom = (100 - (total item in row * fxFlex on item)) / total space between item in row
Example
margin-bottom = (100 - (5 * 19) ) / 4
margin-bottom = (100 - 95) / 4
margin-bottom = 5 / 4 = 1.25%
On Your Code
HTML
<div fxLayout="row" fxLayoutWrap="wrap" fxLayoutAlign="space-between">
<!-- margin-bottom = gt-md = 1.25%, md = 6.5% , sm = 22% !-->
<md-card fxFlex.gt-md="19" fxFlex.md="29" fxFlex.sm="39" fxFlex.xs="100" *ngFor="let recipe of recipes" [routerLink]="['/details', recipe.id]" class="recipe-card">
<md-card-header>
<md-card-title>element</md-card-title>
</md-card-header>
<img md-card-image src="http://placehold.it/350x200">
<md-card-content>
<p>
Lorem Ipsum
</p>
</md-card-content>
</md-card>
</div>
CSS
md-card {
margin-bottom: 6.25%; // md flex 29
// this commented margin is the responsive margin calculation you must implement
// margin-bottom: 1.25%; // gt-md flex 19
// margin-bottom: 22%; // sm flex 39
// margin-bttom : 2%; // sm flex 49 better use this one
}

Input field should take the remaining width

I am trying to build a form to add new users to some kind of entity. The idea is to have user avatars in a line and on the end of the line there is a input-field with a typeahead to insert new users.
I tried this some years ago and ended up using javascript as I was not able to do this in plain css (2).
The big question: is this somehow possible in css3?
Basic idea of code:
<div class="availableWidth">
<div class="list">
<ul>
<li><div class="avatar">...</div></li>
...
</ul>
</div>
<div class="form">
<div class="typeaheadField">
<input ...>
</div>
<button>+</button>
</div>
</div>
CSS:
.list ul li {
list-style-type:none;
display:inline-block;
}
button {
width:50px;
}
Basic Idea is that the box .availableWidth has some width (100%) the box .list grows in width (when new li items are added) as the box .form should shrink in width. Right to the input is a some pixels wide button. The input should take the remaining space.
Is that possible in css3 or will I need Javascript?
You can use flexbox, or you can use display table attributes in CSS. Take a look:
.container {
display: table;
width: 100%;
position:relative;
}
.avatar {
width: 50px;
height: 50px;
display: table-cell;
}
.input {
height: 50px;
display:table-cell;
vertical-align: middle;
}
.input input {
width: 100%;
box-sizing: border-box;
padding: 5px;
}
<div class="container">
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="input">
<input type="text"/>
</div>
</div>
<div class="container">
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="input">
<input type="text"/>
</div>
</div>
You can add all the avatars that you want at left side and the input rearrange automatically.
You want to make input 100% width relative to some container from avatars to button. You can get it by using table, flexboxes or formatting contexts and floats.
Here is last one http://jsfiddle.net/53f0yzeL/
Notice overflow:hidden rule for .avatars-wrapper, it make container to fit exactly between floated elements and .avatars side so you can make input 100% wide.

Resources