CSS: Align children elements like 'filling up columns' - javascript

I have a div-container, which has one main image and optional multiple smaller images: http://jsfiddle.net/h5kc8ybm/
The multiple smaller images are generated dynamically, so there can be just 1 or 10 of them. On my JFiddle you can see, that the images are just displayed in one single row.
What I want to achieve is, that there are filled up 'by colomns':
First image on top next to the main image (like shown in this example)
Second image below that (not right of it, like in the example)
Third image right of first image (top)
Fourth image below third image
...and so on.
Is it possible to do that just with CSS?
Update
To avoid misunderstanding: All smaller images should be positioned right of the main image. But these small images should be displayed in two rows, filled up from first row to second row.
The main div-element will never change its height, but only its width.
Example
HTML
<div class="tnwrapper">
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
</div>
LESS
.tnwrapper {
background-color: #f5f5f5;
padding: 5px 5px 5px 9px;
border-radius: 4px;
display: inline-block;
.tn {
display: inline-block;
vertical-align:top;
position: relative;
margin-right: 5px;
.thumbnail {
display: block;
padding: 4px;
margin-bottom: 20px;
line-height: 1.42857143;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
}
.thumbnail.child {
width: 40px;
}
}
}

I was able to do this with the following steps:
wrap the smaller children in a div and make it position:relative
apply position:absolute on even items and reposition them
float them left
http://jsfiddle.net/0neukb08/
The downside of this approach is that it hardcodes the image's size in the "reposition" step
Additionally, the reason I chose not to use flex-box here was this issue with growing its width (I also didn't like the highest voted answer), but flexbox is a good option if you know the container's width in advance.

You probably can do this by
Rotate the container -90deg and reflect it:
.tnwrapper {
...
transform: rotate(-90deg) scaleX(-1);
}
then apply the reverse transformation for the thumbnails:
.tnwrapper .tn {
...
transform: rotate(90deg) scaleX(-1);
}
JSFiddle: http://jsfiddle.net/h5kc8ybm/1/
Note though that the height limit of the container is now width, not height (because it was rotated -90deg.

CSS flexbox styling should do the trick:
.tnwrapper {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 200px;
}
.tn:first-child {
height: 192px;
width: 192px;
}
<div class="tnwrapper">
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
<div class="tn">
<img src="http://placehold.it/96x96" alt="" class="thumbnail child">
</div>
</div>
EDIT: Sorry, the above snippet doesn't quite answer the question after all. This snippet places each subsequent image in left-to-right then top-to-bottom order, rather than top-to-bottom then left-to-right order as the question asked. I think adding a div around the first image would be the cleanest way to accomplish what you want.

I'm not quite clear on the order of the thumbnails but I think you wanta column format for those.
I that case wrap the main image and the thumbnails in separate divs and then flexbox can do the rest.
.wrap {
display: flex;
margin: 1em auto;
height: 280px;
}
.hero {
padding: 10px;
}
.sidekicks {
flex: 1;
padding: 10px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
}
.sidekicks .item {
width: 96px;
height: 96px;
margin: 10px;
background: lightblue;
line-height: 96px;
text-align: center;
}
<div class="wrap">
<div class="hero">
<img src="http://lorempixel.com/image_output/city-h-c-240-250-5.jpg" alt="" />
</div>
<div class="sidekicks">
<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>
Codepen Demo

This is solution with flexbox and since you said that height of main-div wont change this should work http://jsfiddle.net/h5kc8ybm/13/
CSS
.tnwrapper {
background-color: #000;
padding: 5px 5px 5px 9px;
border-radius: 4px;
display: -webkit-flex;
display: flex;
}
.child-images {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
margin: 0 10px;
height: 170px;
}
.tnwrapper .tn .thumbnail {
padding: 4px;
margin: 10px;
line-height: 1.42857143;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
}
.child-images .tn img {
width: 40px;
}

Related

Positioning an image on top of text

How can I position an image on top text. Like in the image given
Here is a basic example using flex. I put a border on the div so you can see exactly what the flex does. Also, for an example like this where you want the image to be directly over text, you have to lookout for default margins/padding. For example, the <p> element has a default margin which I set to 0.
.row {
display: flex;
flex-direction: column;
border: solid 1px black;
width: 200px;
height: 80px;
padding: 20px;
background-color: #1e3f5a;
}
p {
margin: 0; /* removes default p margin */
text-align: center;
font-size: 30px;
color: white;
}
img {
align-self: flex-end;
margin-right: 1.5rem; /* optional */
}
<div class="row">
<img src="https://dummyimage.com/55x25/ed7014/fff&text=Trending">
<p>Dex Activity</p>
</div>
You can also use the position css property for this, you can wrap these two tags with a div and use the css flex methods.
CSS Flex Example:
<div style="display:flex; flex-direction:column"><img src="IMG_URL" alt="..." style="align-self:flex-end"><p>Dex Activity<p/></div>
There is more than one technique.
Here's one, borrowed from w3schools:
<!DOCTYPE html>
<html>
<head>
<style>
.container {
position: relative;
}
.topright {
position: absolute;
top: 8px;
right: 16px;
font-size: 18px;
}
img {
width: 100%;
height: auto;
opacity: 0.3;
}
</style>
</head>
<body>
<h2>Image Text</h2>
<p>Add some text to an image in the top right corner:</p>
<div class="container">
<img src="img_5terre_wide.jpg" alt="Cinque Terre" width="1000" height="300">
<div class="topright">Top Right</div>
</div>
</body>
</html>

Image width not adjusting width:100%

I have been trying to develop a product page for my website and I have three angles for my product images so I wanted to create a image gallery when you go to the page. The layout I am going with and the code I have so far is at this link https://jsfiddle.net/b1g2f8dh/ . My issue is I want this to be responsive so I want the .main-image img width to shrink with the page as it collapses until it gets to a min-width in which case the .angle-images div i want to shift below the main-image div and with the thumbnails laid out horizontally. My first issue is I cannot get the main image to resize despite i have width 100%. I would have thought it would scale it down as the parent container gets smaller. The second issue is I cannot figure out how to shift the second images beneath. I am getting my positions all mixed up that nothing seems to work! I plan to figure out some javascript so when you click the thumbnail it makes it the main image but thats a problem for another day ha! Any help would be appreciated. The full implementation of my code can be found here in case that helps https://www.printperry.com/home/product-page/index.php
<div class="product-images">
<div class="angle-images">
<li>
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
<li>
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
<li>
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
</div>
<div class="main-image">
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</div>
</div>
.product-images{
max-height: 700px;
max-width: 700px;
width: 100%;
display: block;
}
.angle-images{
padding:5px 0px;
width: 120px;
display: inline-block;
float:left;
max-height: 700px;
}
.main-image{
width: 80%;
height: 600px;
float: left;
margin: 10px;
}
.angle-images li{
list-style: none;
padding-top: 50px;
}
.angle-images img {
width: 100px;
float: right;
margin:5px 10px;
}
.main-image img {
width: auto;
height:700px;
}
There a couple of issues with your CSS preventing it from working as you desire. The height, width, max-width, values you have are working against each other in ways that aren't immediately apparent.
It works after making the modifications below.
Using flexbox for the layout mode makes it easy to switch between column and row layouts based on a media query.
.product-images{
max-height: 700px;
max-width: 700px;
width: 100%;
display: flex;
flex-flow: column nowrap;
flex-direction: column-reverse;
}
#media (min-width: 768px) {
.product-images {
flex-flow: row nowrap;
}
}
.angle-images{
padding:5px 0px;
width: 120px;
max-height: 700px;
display: flex;
}
#media (min-width: 768px) {
.angle-images {
flex-flow: column nowrap;
}
}
.main-image{
width: 80%;
height: 600px;
margin: 10px;
}
.angle-images li{
list-style: none;
padding-top: 50px;
}
.angle-images img {
width: 100px;
margin:5px 10px;
}
.main-image img {
max-width: 100%;
}
Like Dan mentioned in his post, there were conflicting values. One of the issue I saw, was the size of the parent container, and the child container.
I am also learning as well, and one tip I would give you is try to use border-style to help you see visually, it makes problem solving more direct and easy.It really helps when you're working with multiple div container. Then play around with what you know, and try to see how to make it fit. I decided to give a stab at this, and came up with this version. You would have to use Flex unfortunately, it just made problem solving easier. The angle and main are responsive together for now unless you were trying to make just the main responsive only, please let me know so I can take some more time later and see if I further assist you, but for now this is what I have. I hope this leads you to the right path of whatever it is you're trying to achieve.
<div class="product-images">
<div class="angle-images">
<ul class="angle-ul">
<li class="angle-li angle-li-1">
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
<li class="angle-li angle-li-2">
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
<li class=" angle-li angle-li-3">
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</li>
</ul>
</div>
<div class="main-Image">
<img data-image="White" src="https://cdn.ssactivewear.com/Images/Color/17130_f_fl.jpg" alt="">
</div>
</div>
* {
margin: 0;
padding: 0;
}
.product-images {
height: 700px;
max-width: 700px;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: warp;
border-style: dotted;
}
.angle-images {
width: 100px;
border-style: dotted;
}
.angle-ul {
}
.angle-li img {
width: 100%;
}
.main-Image img {
height: 100%;
width: 100%;
}

CSS Grid two rows nested in a single column

I am looking for a way to allow two rows within a single column while the other two columns to the right of it are equal/flexible to the height of those two rows. The width should be 100% when looking at all three columns (so around 33% each column). Here is an example of how I want it to look:
https://i.imgur.com/lLPzXhS.png
I will be filling those boxes with clickable boxes like shown below:
https://i.imgur.com/uyyDbL7.png
I have tried using display: row, display: cell, but I am not able to add any margins to it so this is the product I get:
https://i.imgur.com/Ok6EgT0.png
You can see that I have somewhat of the grid system set up, but not as ideally as I want it. There are no margins that can be set between the red and orange box, even though I am able to add margins to the turqoise and blue box.
Here is the code I have:
HTML:
<div class='d-table'>
<div class='t-row'>
<div class='t-cell one-third'>
<div class='turqoisebox'>
Turqoise box here
</div>
<div class='bluebox'>
Blue box here
</div>
</div>
<div class='t-cell one-third redbox'>
Red box here
</div>
<div class='t-cell one-third orangebox'>
Orange box here
</div>
</div>
</div>
CSS:
.d-table {
display: table;
}
.t-row {
display: table-row;
}
.t-cell {
display: table-cell;
margin-left: unset;
margin-right: unset;
/*border: 1px solid tomato;*/
}
.one-third {
width: 30%;
}
.two-thirds {
width: 200px;
}
.bluebox {
background-color: #9dd8dd;
margin: 25px;
border-radius: 25px;
border: solid #7dacb0;
border-width: 3px;
box-shadow: 2px 4px 8px 2px rgba(0,0,0,0.4);
transition: 0.3s;
text-align: center;
}
.bluebox:hover {
box-shadow: 2px 8px 16px 2px rgba(0,0,0,0.8);
}
Any thoughts on how to replicate the second image results neatly?
You could use flexbox. Take a look at this simplified example:
.content {
background: orange;
margin: 1rem;
padding: 1rem;
flex: 1;
color: white;
display: flex;
}
.content > span {
margin: auto;
}
.row {
display: flex;
flex-direction: row;
background-color: blue;
flex: 1
}
.col {
display: flex;
flex-direction: column;
flex: 1;
background-color: red;
}
<div class="row">
<div class="col">
<div class="row">
<div class="content">
<span>This is centered</span>
</div>
</div>
<div class="row">
<div class="content">
<span>This is centered</span>
</div>
</div>
</div>
<div class="col">
<div class="content">
<span>This is centered</span>
</div>
<div class="content">
This is not
</div>
<div class="content">
This is not
</div>
</div>
<div class="col">
<div class="content">
This is not
</div>
<div class="content">
This is not
</div>
<div class="content">
This is not
</div>
<div class="content">
<span>This is centered</span>
</div>
</div>
</div>
You could also use a minimal flexbox-based grid library like Flexbox Grid.
Margin is used for setting where elements should start so instead use padding between those 2 elements to get the space you want.

How to highlight and detect mouse clicks on a css grid row?

I'm trying to create a menu which I'm laying out using CSS grid. The problem that I'm having is figuring out how I can make the menu interactive when the mouse is hovering over each menu item.
I would like to be able to highlight the entire row when the mouse is over any of the menu items in the row. I can highlight each individual grid cell by adding a :hover css rule, but I don't know how to highlight the entire grid row.
The second part is then detecting when a row is being clicked. Again, I can add an onClick event handler to each cell but that doesn't seem ideal, as users could accidentally click in the gap between grid cells. I was thinking that if I can figure out how to highlight the entire row, then i could add the click handler to this row highlighter and that would solve the gap click problem.
I have created a codepen example that demonstrates how the menu is currently constructed: https://codepen.io/marekKnows_com/pen/RqMgGw
HTML:
<div class="myGrid">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
</div>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
</div>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
<div class="anchor" id="item3"></div>
<span class="text">Action</span>
<div class="separator"></div>
<div class="anchor" id="item4"></div>
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
CSS:
.myGrid {
border: 1px solid black;
display: grid;
grid-template-columns: 20px auto auto;
grid-gap: 2px 6px;
align-items: center;
justify-items: start;
padding: 10px;
box-sizing: border-box;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
justify-self: end;
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
One option is to wrap the row elements with a div, include style display: contents; in the wrapper div, add the click handler to the wrapper div.
CSS grid will treat the elements inside the wrapper as if there was no wrapper when laying out the contents, so they will be aligned as you desire. See MDN display-box for more info. That link also points out browsers have accessibility bugs with display: contents;.
I have tested only with Firefox so far.
<div class="myGrid">
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
</div>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
</div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
</div>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
</div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item3"></div>
<span class="text">Action</span>
</div>
<div class="separator"></div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item4"></div>
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
</div>
.myGrid {
border: 1px solid black;
display: grid;
grid-template-columns: 20px auto auto;
grid-gap: 2px 6px;
align-items: center;
justify-items: start;
padding: 10px;
box-sizing: border-box;
}
.row {
display: contents;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
justify-self: end;
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
I finally got it to work. What I ended up doing was making the anchor element have position relative. Then I added a new div with position absolute under the anchor element. From within JavaScript I can size the new element to be the full width of the grid and using z-index I can position it relative to the other elements in the row accordingly.
Firstly, you might want to change your html so the .anchor elements are wrapping each item.
<div class="myGrid">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
</div>
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
</div>
<div class="anchor" id="item3">
<span class="text">Action</span>
</div>
<div class="separator"></div>
<div class="anchor" id="item4">
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
</div>
And then use flex to align the contents of each item
.myGrid {
border: 1px solid black;
padding: 10px;
box-sizing: border-box;
}
.anchor {
display: flex;
justify-content: flex-start;
}
/* Hover for each anchor */
.anchor:hover {
background: red;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
margin-left: auto; /* push the shortcut to the right */
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
https://codepen.io/anon/pen/xQWLaE
.anchor:hover >
.mygrid
{ background:red }
check this if it works on hovering item1 it will change the border color(from black to red as highlighting)

CSS - Automatically adjust width of div

I have a dropdown bar with a bunch of options available to select. I want them to be inline but also want them to be scale-able so that they take up the entire width of the div (but also allowing multiple options per row). This is a photo of what I have so far:
Here is the html I have:
<h2>FILTERs</h2>
<span>Search:</span>
<input id="searchBox" type="text"></input>
<div id="conts" class="filter">
<div class="label">
<span>Option:</span>
</div>
<div class="content">
<div class="selector">Di1</div>
<div class="selector">Di 12</div>
<div class="selector">D 15</div>
<div class="selector">Div1</div>
<div class="selector">v1234</div>
<div class="selector">Di 3</div>
<div class="selector">D 12</div>
<div class="selector">v 1234</div>
<div class="selector">Di</div>
<div class="selector">D 123</div>
</div>
</div>
and the CSS:
.filter .content{
max-width: 96px;
max-height: 0px;
margin: 0px 12px 0px 4px;
background-color: #808080;
overflow: hidden;
}
#vertnav .filter:hover .content{
max-height: 256px;
}
.content .selector{
background-color: #369;
padding: 8px 4px;
display: inline-block;
text-align: center;
cursor: pointer;
box-sizing: border-box;
transition: .1s !important;
}
.content .selector:hover{
background-color: white;
color: #369;
}
The end goal is that each <div> on the same line will automatically fill the width of the row it is on, while not pushing the other <div>s onto a new line (aka, not using display: block; for example).
I am willing to use JS or jQuery but would prefer to use html and css only for this.
Thank you.
This is a typical situation for using flexbox:
Define the container as flex-container and give it these settings:
content {
display: flex;
flex-wrap: wrap;
}
(The first setting will do the equal distribution in lines, the second one will put the flex items (children elements) into several lines)

Categories