Nested flexboxes and items alignment - javascript

I'm trying to create my own small grid system based on CSS3 flex display. I basically have the following classes:
a grid class, which is a flex container with flex-direction set to column.
a row class, which is a flex container with flex-direction set to row.
set of column classes of different flex-basis sizes.
What I want is to be able to align each row to the left/center/right by setting the self-align property of the row element. However, whenever I try to do it, things seem to go bad.
Here is a plunker that demonstrate it:
http://plnkr.co/edit/mHOs7U28GCBJuPvi7ikJ?p=preview
HTML
<!-- first row -->
<div class="row align-end"> <!-- try to remove 'align-end' here -->
<div class="column-1">
<div class="item">1</div>
</div>
<div class="column-1">
<div class="item">2</div>
</div>
</div>
<!-- second row -->
<div class="row">
<div class="column-1">
<div class="item">3</div>
</div>
<div class="column-2">
<div class="item">4</div>
</div>
</div>
</div>
CSS
* {
box-sizing: border-box;
}
.grid {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
.column-1 {
flex-basis: 33.33%;
padding: 10px;
}
.column-2 {
flex-basis: 66.67%;
padding: 10px;
}
.column-3 {
flex-basis: 100%;
padding: 10px;
}
.align-start {
align-self: flex-start;
}
.align-center {
align-self: center;
}
.align-end {
align-self: flex-end;
}
.item {
background-color: lightblue;
font-family: "Arial";
text-align: center;
padding: 4px;
}
As you can see, In this plunker I set up a grid with two rows, with two columns in each row. The two columns in the first row have a width of 33.33% (flex-basis). In the second row, the first column's width is 66.67% and the second column is 33.33%. Now, since the first row has some unused space, I want to try to align it to the right (for whatever reason). Therefore, I add to the div that represents the first row the class align-end, which basically just adds the property align-self: flex-end; to the element.
As you can see, by doing so the first row looks bad, both columns are aligned to the right, but their width is totally corrupted (you can try and remove the class 'align-end' from the first row, and things will get back to normal).
What am I missing? Why the row doesn't align correctly to the right?
Thanks,
Roy.

The property that controls how the children are aligned along the main axis is justify-content
.align-end {
justify-content: flex-end;
}
plunker

is this whats you're going for?
http://plnkr.co/edit/bFWMSQ7qj4Cuomzm0Ptv?p=preview
Looks like you had 2 column-1 class in the first row
<!-- first row -->
<div class="row align-end"> <!-- try to remove 'align-end' here -->
<div class="column-1">
<div class="item">1</div>
</div>
<div class="column-1">
<div class="item">2</div>
</div>
</div>
********edit*********
after some digging i think i know what you mean.
you are trying to left align the first box and right align the second box leaving a blank in the middle.
if you add margin-left: auto; it takes care of the rest of the space left in the row.
http://plnkr.co/edit/1Eoeh4uOik3BIZHsL9bH?p=preview
i added it to the align-end class so whenever you use align-end, it will add the margin-left:auto; to that box.

Related

Show/hide a div child on hover without javascript

i have a bunch of repeating cards:
<div id="container">
<div class="card">
<div class="card_img"><img src="/img.jpg"></div>
<div class="card_text">Title</div>
<div class="card_moreinfo">More info</div>
</div>
...
<div class="card">
<div class="card_img"><img src="/img.jgp"></div>
<div class="card_text">Title</div>
<div class="card_moreinfo">More info</div>
</div>
</div>
the container style is something like:
.container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
}
the card style is something like:
.card {
flex: 0 0 13em;
}
my goal is to have the more info text (div), appear when i hover the card; since the cards contain a product coming from the database i can surely add the product id as class both in card and in moreinfo and target it by name with a javascript, but im wondering if i can change the display of the div, targeting it as the child of the div im hovering
.card_moreinfo {
display: none;
}
.card_moreinfo:hover + card_moreinfo{
display: block;
}
source: Using only CSS, show div on hover over <a>
You need to use the :hover for displaying or hiding the child.
Example;
.card_moreinfo{
display: none;
}
.card:hover .card_moreinfo{
display:block;
}
.card {
flex: 0 0 13em;
}
.card:hover {
/*add your css*/
}

How to repeat character in HTML with responsive resizing?

I am trying to create rows in a DIV where there are three pieces of information to display. A left align text, a right align text, and repeat character "." between the two
I tried this using the HTML below. But it is not working with a div for each piece.
<div style="margin-bottom:5px"><!-- row 1 -->
<div style="float:left;">Left</div> <!-- left column -->
<div style="display: inline-block;">...</div> <!-- center column -->
<div style="float:right;">Right</div> <!-- center column -->
</div><!-- row 1 -->
I believe it most likely has to be done using just one div displaying one piece of text/string where the "." character gets repeated between the other two pieces of text. I cant figure it out so that the string changes with the DIV size - in order to keep it responsive.
You could achieve that rather simply with flexbox and a dotted border.
.row { display: flex; }
.center {
flex-grow: 1;
border-bottom: 2px dotted black;
margin: 0 4px 4px;
}
<div class="row">
<div class="left">Left</div>
<div class="center"></div>
<div class="right">Right</div>
</div>
<div class="row">
<div class="left">This is some longer left text</div>
<div class="center"></div>
<div class="right">Right</div>
</div>
<div class="row">
<div class="left">Left</div>
<div class="center"></div>
<div class="right">This is some longer right text</div>
</div>
Make parent display: flex so that children align side-by-side.
Add flex-grow: 1 to the center so that it fills empty space
Add border-bottom: 2px dotted black to achieve your dotted line
Add some margins to position and pad the dotted line properly
You could do something like this :
<div class="row>
<div class="left"> Left </div>
<div class="middle"></div>
<div class="right"> Right </div>
</div>
And use flexbox to set the sizes:
.row { display: flex; }
.left , .right { flex: 0 0 auto; } /* will not shrink or grow, with their default width set to auto */
.middle { flex: 1 1 0; } /* will shrink/grow to fill all available space, with a default width of 0 */
Now, you could apply something like:
.middle {
position: relative;
border-bottom: 1px dotted currentColor;
transform: translateY(-.4em); /* change to reposition vertically */
}
You can also add spacing by :
.left { padding-right: 1em; }
.right { padding-left: 1em; }

Is there any other way to change styles than to override each of them?

There is really many panels on my site. Each of them has a div with items-container class and inside of it there is a few item divs (all you can see in example code below). To style them all I created "global" styles (let's call them global) which work on all panels, but there are a few I want to have different styles.
To change the styles of top-container panel, I need to copy all global styles and override every single one of them under new selector (top-container).
Is there any other way to change the styles of my top-container panel than to override each of it separately?
JS solutions are also welcome (if there are any...).
Here is a demo: LINK
And here is the code:
<div class="top-container">
<div class="top panel">
<div class="items-container">
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
</div>
</div>
</div>
<div class="middle">
<div class="left panel">
<div class="items-container">
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
<div class="item">Item5</div>
<div class="item">Item6</div>
<div class="item">Item7</div>
<div class="item">Item8</div>
</div>
</div>
<div class="right panel">
<div class="items-container">
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
<div class="item">Item5</div>
<div class="item">Item6</div>
<div class="item">Item7</div>
<div class="item">Item8</div>
</div>
</div>
</div>
CSS:
.top-container {
width: calc(100% - 4px);
height: 50px;
}
.panel {
border: 2px solid black;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.middle {
width: 100%;
height: 250px;
display: flex;
flex-direction: row;
margin-top: 10px;
}
.items-container {
display: flex;
flex-direction: column;
text-align: center;
}
.item {
font-weight: bold;
}
.top-container .items-container {
display: block;
}
.top-container .items-container .item {
display: inline-block;
}
I write the styles in SASS, but jsfiddle somehow didn't work even when I changed the language.
This is a simple example. I know it's not much work to change two lines of code (in this case), but my real project is much more complicated and overriding styles = hundreds of additional lines of code...
As you mentioned !
To change the styles of top-container panel, I need to copy all global
styles and override every single one of them under new selector
(top-container).
The easiest way is to make a global class which you already did .panel. Now if you want to give any of panels a different style, either add a new class <div class="top panel panel1"> or select by child selector .middle > .left or select by nth-Child().
Here is your updated Fiddle with my example.
Hope it will answer your question.

How do you "stack" flex elements that are in seperated columns?

I've displayed my elements using the flex property and flex-flow: column nowrap. I've made quick display of what my elements look like :[this]
So obviously I can't just stack both of the column on top of each other because I'm using ajax call to number each element, my left column is for even number and the right one for odd numbers. I'm wondering how I could achieve this without breaking my code. I'm doing this so that it can be responsive for mobile users.
I dont get why you want to do it this way?
You could just make it into rows, with a placeholder that you remove, when screen size gets to small. That way, you can keep it all simple and clean.
- container
-- row
--- box
--- placeholder
--- box
--- placeholder
Like this: http://jsfiddle.net/d9jg1p2s/
EDIT: Forgot to remove placeholders on mobile size.
Here you go: http://jsfiddle.net/d9jg1p2s/1/
There is no method to merge containers in flexbox but there is a method for the containers to be treated as though they were not there.
It's display:contents
Browsers (excepting Firefox) will remove any element with a display value of contents set on it from the accessibility tree. This will cause the element and all its descendant elements to no longer be announced by screen reading technology.
MDN
Support, unfortuately, is not universal but is growing.
Then..just align each alternate element in the "new" column to align-self: flex-end;
* { margin: 0; padding: 0; box-sizing: border-box; } ::before, ::after { box-sizing:inherit; }
.box {
display: flex;
justify-content: center;
align-items: center;
width:150px;
height:150px;
border:2px solid rebeccapurple;
}
body {
width: 55%;
min-width:150px;
margin:1em auto;
border:1px solid limegreen;
display: flex;
flex-direction: column;
}
.box:nth-child(odd) {
align-self: flex-end;
}
.container {
display:contents;
}
<div class="container">
<div class="box">1</div>
<div class="box">3</div>
<div class="box">5</div>
<div class="box">7</div>
<div class="box">9</div>
<div class="box">11</div>
</div>
<div class="container">
<div class="box">2</div>
<div class="box">4</div>
<div class="box">6</div>
<div class="box">8</div>
<div class="box">10</div>
<div class="box">12</div>
</div>

Aligning divs using the baselines of child divs in css

I can align two div's by simply setting their display to inline-block and using same line-heights like shown in the below:
However, what I want is that aligning two nested divs according to the baseline of the inner divs like this:
I can achieve this also using jquery by taking the longest heading's height and set all the headings' height to this value.
var fitSizes = function () {
var h = 0;
$('h1').each( function(){
if(h < $(this).outerHeight()) h = $(this).outerHeight();
// select biggest height
});
$('h1').each( function(){
$(this).outerHeight(h);
// set all h1 heights to the biggest height
});
};
fitSizes();
But for some reasons I don't want to use js or jquery. Is there any "CSS only" way to achieve something like that?
Any solution I can think of here seems hacky, as are usually problems of this nature. There is ALWAYS a scenario where they will break. A programmatic approach, however bloated and ugly, will definitely give you exactly what you want.
I'm going to make an assumption that both the header and the content are of varying lengths and there may be more than just 2 on page either on a single line or multiple.
TOP DOWN APPROACH // fixed header height
There's no reason why your approach above won't work for a nested div. I would wrap the h1 if you're applying styles to it though. Setting a line-height on a h1 if it breaks across lines will cause each line in the multiline to have that line height. Wrap the header in a div and give that a static height, that way if the has styles such as a background won't be affected by the "margin".
<style>
.wrapper {
height: 2.5rem;
line-height: 2.5rem;
text-align: bottom;
// flex approach works too
}
h1 {
line-height: 1rem;
}
</style>
...
<div class="container">
<div class="wrapper">
<h1>title</h1>
</div>
<div class="content">
<p>lorem ipsum....</p>
</div>
</div>
"BOTTOM UP" APPROACH // fixed content
This would work better if the "anchor" for these components is the bottom of the page. If your content varies in length you could fix the height of the container and content.
<style>
.container {
text-align: bottom;
}
h1 {
line-height: 1rem;
}
.content {
height: 15rem;
overflow: elipsis;
}
</style>
...
<div class="container">
<h1>title</h1>
<div class="content">
<p>lorem ipsum....</p>
</div>
</div>
You could do it with flexbox, you could set make the outer div's siblings by making a container around them and do something like this:
.container {
display: flex;
align-items: flex-end;
}
If this does not fulfill your needs you could also try and see if align-items: baseline; fixes it. Just have a look at flexbox.
What You are looking for using flexbox.
.root {
display: flex;
height: 300px;
border: 2px solid black;
}
.container {
display: flex;
/* position at bottom of container */
margin-top: auto;
/* spread inside container */
flex-grow: 1;
/* align items in row and center it verticaly */
flex-direction: row;
justify-content: center;
}
.column {
display: flex;
margin: auto 5px 5px;
padding: 20px;
/* spread inside container */
flex-grow: 1;
/* align items in column, and position content at the bottom */
flex-direction: column;
justify-content: flex-end;
border: 2px solid blue;
}
.row {
margin: 5px;
padding: 10px;
border: 1px solid red;
text-align: center;
}
<div class="root">
<div class="container">
<div class="column">
<span class="row">row one</span>
</div>
<div class="column">
<span class="row">row one</span>
<span class="row">row two</span>
</div>
</div>
</div>
Flexbox is something up and coming that would be really useful to use. It's only growing in popularity.
This can answer many different problems. Such as your justification issue.
Here's a simple fiddle with little code that shows the answer to your problem: https://jsfiddle.net/hkLk53c6/
HTML:
<div class="container">
<div class="flex-item">
Item
</div>
<div class="flex-item">
Item
<br>
Item
</div>
<div class="flex-item">
Item
<br>
Item
<br>
Item
</div>
</div>
CSS:
.container {
display:flex;
justify-content: space-between;
border: 1px solid #333;
}
.flex-item {
width: 33%;
text-align: center;
background: #120321;
color: #fff;
}
Here's a link to Chris Coyier's explanation about Flexbox Properties:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
I've personally found it very useful in learning more about flexbox.
You can styled based off of the baseline, you can reverse elements, justify them to be the same height both vertically and horizontally. Etc. It's very exciting because now we can get past some hacky fixes. (Like using JS which trust me, you're not the only one to do so far!)

Categories