I have partially stacked two images using CSS Grid. The image that the user hovers over increases in z-index and therefore overlays the other. Users can switch back and forth between those two images.
Now I am wondering if it's possible to give the image that it is currently in "focus"/has the higher z-index a box-shadow that appears/disappears, depending which image is on top. Is that even possible using CSS only?
Example of what I mean. And the grey layer seems to have a shadow.
http://vrscigroup.com
You can't achieve this with CSS only, you need something that tells CSS which is the card with the higher z-index, after that you can apply a class.
I would add something with js (jquery maybe?) that adds a class and use that class to add the box shadow, something like this:
$('.cards').hover(function() {
// remove it from all cards
$('.cards').removeClass('box-shadow');
// add it to the one on hover only
$(this).addClass('box-shadow');
});
After that just add the css class:
.cards.box-shadow {
box-shadow: 0 0 20px #000;
}
Of course, that's just an example :)
Use :hover pseudoclass here instead of JavaScript. Demo:
.grid {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
}
/* overlapping grid items */
.item-1 {
grid-row: 1 / 3;
grid-column: 1 / 3;
background-color: green;
}
.item-2 {
grid-row: 2 / 4;
grid-column: 2 / 4;
background-color: yellow;
}
/* setting higher z-index on hover */
.item-1:hover {
z-index: 1;
}
/* adding box shadow */
.item:hover {
box-shadow: 0 0 10px #000;
}
<div class="grid">
<div class="item item-1"></div>
<div class="item item-2"></div>
</div>
Related
I want to build a grid that could, for example, look like this:
Each item is manually given its grid-row, for example the item D has grid-row: 6
If a row contains only one item, that item should span across the entire row, like the item A
If a row contains multiple items, or in other words the items "overlap", they should share the row's space equally, like items B and C or D, E and F
The grid-column property should NOT be given to items manually, for example I do not want to manually give the item F grid-column: 5 / 7. This is because items will be inserted into the grid one after the other, and when an item is inserted or removed the other items should adjust accordingly.
My current approach (that doesn't work) is this:
.grid {
height: 300px;
width: 300px;
display: grid;
border: 1px solid red;
}
.item {
border: 1px solid teal;
}
.item-a {
grid-row: 1;
}
.item-b {
grid-row: 2 / 4;
}
.item-c {
grid-row: 3;
}
<div class="grid">
<div class="item item-a">a</div>
<div class="item item-b">b</div>
<div class="item item-c">c</div>
</div>
As you can see, the item a does not span across the entire row. Giving every item grid-column: span 2 just adds new columns and doesn't change the layout.
How can I achieve the desired grid?
I have made up a grid layout that consists of 3 columns wide and 3 rows tall:
.home-works {
padding: 30px;
font-size: 1.2rem;
display: grid;
grid-template-columns: 2fr 2fr 2fr;
grid-template-rows: 2fr 4fr 4fr;
grid-gap: 10px;
}
This is giving me zero problems at desktop view, but what I need to follow up with, now, is when the view port breaks, at the moment I'm working with a max-width:768px rule. So, right now, once the view port breaks to that max-width, any CSS Grid command doesn't seem to have an effect or a change. I have tried using grid-row or grid-row-start grid-column or grid-row-start but no luck.
This is my HTML for the layout:
<div class="home-works">
<div class="head">
<h1>Let's stay connected!</h1>
</div>
<div class="col-menu">
<img class="image-home" src="img/profile-picture.png" width="50%">
<ul>
<li>home</li>
<li>about</li>
<li>contact</li>
<li>downloads</li>
</ul>
</div>
<div class="main-content">
<p>This is my website and I call it, the <em>"glassless window"</em>
Why? Because using the frame on your device (mobile, desktop or laptop)
we are allowed to establish a connection thus enabling me to show you my
up and coming projects. </p>
</div>
<div class="caption-object">
<p>I really wish you could <a class="drop-a-line-link" href="#">drop me a line</a> somewhere
in the future!</p>
</div>
</div>
And this is the CSS for the distribution:
.head {
grid-column: 1 / 4;
text-align: center;
}
.col-menu {
grid-column: 1;
grid-row: 2 / 3;
}
.main-content {
grid-column: 2 / 4;
grid-row: 2 / 3;
}
.caption-object {
grid-column: 3 / 4;
grid-row: 3;
}
This is my first time going about media queries and CSS Grid, meaning this is the first time i input a grid command inside a media query rule set. I checked to see if this would happen too if I wanted to change the background-color: plum; and it did worked. I know about repeat(minmax()) but honestly I wouldn't know how to properly achieve the same look or if it would have the same 'layout design' because then I'd have to delete the grid row's and column's placement? Like I said this is my first time ever using CSS Grid with media queries, I have attached some pics, thanks!
Initially I decided not to include it because nothing had seemed to be working so I didn't have a reason to include.
#media only screen and (max-width: 768px) {
.nav-items {
flex-direction: column;
align-items: center;
}
.navbar {
height: 200px;
padding-bottom: 20px;
}
.footer-link {
align-self: center;
left: 0;
top: 0;
}
.main-container {
flex-flow: column wrap;
margin: 0 10px;
}
.drop-a-line-link {
text-decoration: underline wavy;
}
}
Media Query
To answer my own question this is what I did and its available on MDN, have to check "Redefining the grid using media queries" topic.
To reorganize a CSS Grid layout one must set up the media query rule (which in this case I had it different than on MDN archives but somehow still worked) and in there I had to reassign my grid-template-areas, which was also another thing I lacked, I was NOT using grid-areas, I had stuff like grid-row or grid-columns. Apparently this seems to be a huge factor that comes to play when we are inside our Media Query code. One thing that they do note as important, when working with grid-areas is that one should assign them, outside of any Media Query commands, to cover just one "row" or one "column", I guess depends on your current grid-auto-flow command, which at default is set as row while defining the columns and rows
So, mine is looking like this:
display: grid;
grid-template-columns: 1fr;
grid-template-rows: minmax(350px, auto);
grid-template-areas:
"header"
"menu"
"main"
"caption";
Since I had not defined any areas on my previous grid I would never have gotten it to work the way I intended for it to behave. Well, and then once in the MQ, you assign the grid as best you can, but first, you need to use grid-template-areas to re-assign the areas, and as well as your columns, using grid-template-columns, this depends on your layout and item sizes or basically it depends on the idea that you had for the grid.
So my Media Query code ended up looking like this:
#media (min-width: 500px) {
.home-works {
grid-template-columns: 2fr 2fr 2fr;
grid-template-areas:
"header header menu"
". main main"
". . caption";
}
}
#media (min-width:700px) {
.home-works {
grid-template-areas:
"header header header"
"menu main main"
". . caption";
}
}
Important: the "." are "white-space", or "negative space" or "empty cells".
I'm trying to solve a grid problem with how the elements are automatically placed in the rows not in the way I intend them to. The code is the simplest possible variation written to demonstrate the issue. The number of paragraphs is variable-length, there can be any amount of them.
div {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
p:nth-child(4n + 1) {
grid-column: 1 / span 1;
}
p:nth-child(4n + 2) {
grid-column: 2 / span 1;
}
p:nth-child(4n + 3) {
grid-column: 2 / span 1;
}
p:nth-child(4n) {
grid-column: 1 / span 1;
}
<div>
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<p>Test5</p>
<p>Test6</p>
<p>Test7</p>
<p>Test8</p>
<p>Test9</p>
<p>Test10</p>
</div>
Here is the current result, with two arrows showing what I want to achieve:
And here is exactly what I want to achieve, created for presentation purposes by just reordering HTML elements in a basic grid:
Thank you in advance!
This can be solved with the grid-auto-flow: dense CSS rule on the grid parent. This has the effect that previously blank cells will be filled, rather than searching for the next available space.
I'm experimenting with component driven front end frameworks, such as Angular, and finally learning CSS Grid.
My question is: is it bad practice to nest CSS Grids?
What I've done here is in my main/root component, I've used css grid to make two things: the navbar and the main content area, since navbar will be present in the entire app and also the main content.
As you can see below, the grid on the root level then another grid in the <nav-bar> component. And in the main content area, there will be many more, probably a grid in each/any Angular component I use.
********************** ******************************
* Navbar * => * img | nav | logout *
********************** ******************************
**********************
* *
* Content *
* *
**********************
Example code below:
app.component.html
<div class="container">
<div class="item-navbar"></div>
<div class="item-nav">
<nav-bar></nav-bar>
</div>
<div class="item-content">
<router-outlet></router-outlet>
</div>
</div>
<!-- With this CSS: -->
<style>
.container {
display: grid;
grid: ". nav ."
". content ."
/ 3vh auto 3vh;
row-gap: 1vh;
}
.item-navbar {
grid-area: 1 / 1 / 2 / 4;
position: relative;
z-index: -1;
background: #579C87;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}
.item-nav {
grid-area: nav;
}
.item-content {
grid-area: content;
background: #D1C7B8;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}
</style>
then
nav-bar.component.html
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" routerLink="/">
<div class="img">
<img src="logo.jpg">
</div>
</a>
</div>
<div class="navbar-menu">
<a routerLink="/dashboard" class="navbar-item">Dashboard</a>
</div>
<div class="navbar-logout">
<a routerLink="/logout" class="navbar-item">Logout</a>
</div>
</nav>
<!-- with this CSS: -->
<style>
.navbar {
display: grid;
grid-template-columns: 64px auto auto;
grid-template-rows: auto;
grid-template-areas: "image navs logout";
gap: 1vh;
}
.navbar-brand {
grid-area: image;
place-self: center / start;
}
.navbar-menu {
grid-area: navs;
place-self: center start;
}
.navbar-logout {
grid-area: logout;
place-self: center end;
}
</style>
There is nothing wrong or invalid with nesting grid containers.
The grid specification doesn't prohibit, or even admonish, against the practice. It says this:
Grid containers can be nested or mixed with flex containers as necessary to create more complex layouts.
In fact, nesting grid containers is what you must do to apply grid properties to the descendants of a top-level container, since grid layout works only between parent and child elements.
More details here:
Grid properties not working on elements inside grid container
Positioning content of grid items in primary container (subgrid feature)
It is not bad practice, it is recommended for proper display.
I have one caveat to mention, separate each nested level into its own file for debugging purposes. When nesting multiple levels deep, a single missing or misplaced </div> can significantly alter the output and will be very hard to debug. My suggestion is any further nesting also should be split out into separate components, so each level can be tested independently.
To answer your question, it is an acceptable practice to nest grid or flex components: csswg
Here is an example that demonstrates a nested grid: gridbyexample
Nesting grid containers is an acceptable practice.
I am trying to build "adjustable" css grid. I am making my blog and i want my news to be displayed in "blocks" and that they me placed like this :
http://pokit.org/get/img/1dfa7b74c6be5bee6c92b886e0b8270b.jpg
And not like this what i did made here
Here is my code.
HTML
<div id="wrapper">
<div class="d_1">1</div>
<div class="d_2">2</div>
<div class="d_3">3</div>
<div class="d_4">4</div>
<div class="d_5">5</div>
<div class="d_6">6</div>
</div>
CSS
#wrapper{
width:200px;
}
#wrapper div{
background-color:lightgray;
width:50px;
float:left;
margin:0px 5px 5px 0px;
}
.d_1{
height:60px;
}
.d_2{
height:30px;
}
.d_3{
height:33px;
}
.d_4{
height:70px;
}
.d_5{
height:60px;
}
.d_6{
height:40px;
}
I suppose that is not possible to obtain the desired result simply using one of the known layout modes (flexbox, grid-layout, inline, ...) nor using CSS columns. Every solution will lead to an unwanted result.
But you can obtain the result using a combination of CSS grid-layout and Javascipt code.
This is the wrapper CSS style block:
#wrapper{
width: 200px; /* CSS grid-layout will expand contained divs to cover this size */
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* "1fr" for each column */
grid-column-gap: 10px;
grid-row-gap: 5px;
}
And this is the Javascript code (add it after #wrapper is closed):
"strict mode";
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
function compute_gaps(a) {
let max = a.max();
return a.map(function(el) {
return el - max;
});
}
function compose_gaps(a, b) {
return b.map(function(el, i) {
return a[i] + el;
});
}
var counter = 0;
var columns = 3; // number of columns
var gaps = [];
var heights = [];
for (let el of document.querySelectorAll("#wrapper > div")) {
let colIdx = counter % columns;
if (counter % columns === 0) {
//compute gaps
if (counter) gaps.push(compute_gaps(heights));
if (gaps.length > 1) {
gaps[gaps.length - 1] = compose_gaps(
gaps[gaps.length - 1],
gaps[gaps.length - 2]
);
}
heights = [];
}
if (gaps.length) {
el.style.marginTop = gaps[Math.floor(counter / columns - 1)][colIdx];
}
heights.push(el.offsetHeight); // apply gap as margin
counter++;
}
Tested the code in a little more complex situation and worked in this way.
The code computes, in each row, gaps between the highest block and the others in the row (compute_gaps); after that, applied the gap as a CSS margin-top. Gaps are summed with the previous ones (compose_gaps).
I hope this answers your question.
Warning:
I am not the best at CSS and JS right now. I tend to brute force things until they work. I am pretty sure this is not the best solution, however, I want to post it so that maybe others can improve upon it. This may not be functional once all content is put in or may not by responsive or may not be dynamic enough to solve the issue, I don't know. I do know that the desired look from the question is achieved through this method, right now, without content etc.
I do welcome any and all feedback regarding why this isn't the best and/or what is wrong with it so I can learn.
With that being said, here is the fiddle:
http://jsfiddle.net/jz4p4Lzk/13/
HTML
<div id="wrapper">
<div class="d_1" id="d1">1</div>
<div class="d_2" id="d2">2</div>
<div class="d_3" id="d3">3</div>
<div class="d_4" id="d4">4</div>
<div class="d_5" id="d5">5</div>
<div class="d_6" id="d6">6</div>
CSS
#wrapper{
width:200px;
}
#wrapper div{
background-color:lightgray;
width:50px;
position:relative;
margin:0px 5px 5px 0px;
}
.d_1{
height:60px;
}
.d_2{
height:30px;
}
.d_3{
height:33px;
}
.d_4{
height:70px;
}
.d_5{
height:60px;
}
.d_6{
height:40px;
}
JS
var d1 = document.getElementById('d1');
var d1Loc = d1.getBoundingClientRect();
var d2 = document.getElementById('d2');
var d2Loc = d2.getBoundingClientRect();
var d3 = document.getElementById('d3');
var d3Loc = d3.getBoundingClientRect();
var d4 = document.getElementById('d4');
var d4Loc = d4.getBoundingClientRect();
var d5 = document.getElementById('d5');
var d5Loc = d5.getBoundingClientRect();
var d6 = document.getElementById('d6');
d2.style.left = d1Loc.right -5+ "px";
d2.style.top = - d1.offsetHeight - 5 + "px";
d3.style.left = d2Loc.right + d1Loc.right -10 +"px";
d3.style.top = - d1.offsetHeight - d2.offsetHeight - 10 + "px";
d4.style.top = - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight + 50 + "px";
d5.style.top = - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight - d4.offsetHeight + 15 + "px";
d6.style.top = - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight - d4.offsetHeight - d5.offsetHeight +12.5 + "px";
d5.style.left = d4Loc.right -5+ "px";
d6.style.left = d5Loc.right + d4Loc.right -10 + "px";
If you don't care about old browsers support (doesn't work with IE9 or above) then you can reorder your divs vertically by using the CSS3 column-count Property and setting it to 3 columns :
Add this to #wrapper :
-webkit-column-count: 3;
-webkit-column-fill: auto;
-moz-column-count: 3;
-moz-column-fill: auto;
column-count: 3;
column-fill: auto;
Then replace float:left; in your #wrapper div by display: inline-block;
Here is a CODEPEN DEMO.
NOTE: If browser support and div order are important then an elegant solution may be found in this StackOverFlow post : how to replicate pinterest.com's absolute div stacking layout
you know that there is an actual "css grid" that you can use? It doesn't quite work yet in IE (it does, but only somewhat), but in all other relevant browsers it works well. Basically, you specify gridlines and then place the boxes that you want to within them.
I made a codepen so you can see it in action. (oh, and no javascript needed)
https://codepen.io/quibble/pen/NaKdMo
#wrapper{
display:grid;
grid-gap:10px;
grid-template-columns:50px 50px 50px;
grid-template-rows: 30px 3px 27px 13px 17px 40px; /*the pixels add up to the corresponding bottoms of each grid container. There are a few ways to do this but I like this one.*/
grid-template-areas:
/*This allows you to specify which grid blocks go where. Notice that some are repeated, this just means they span two or more grid areas. For example, box 3 is 33 px so must span one column and two rows (the 30 and 3px one)*/
"one two three"
"one five three"
"one five six"
"four five six"
"four five ."
"four . .";/* the . is for a blank gridspace */
}
#wrapper>div{
background-color:gray;
}
.d_1{
grid-area:one;
}
.d_2{
grid-area:two;
}
.d_3{
grid-area:three;
}
.d_4{
grid-area:four;
}
.d_5{
grid-area:five;
}
.d_6{
grid-area:six;
}
I'm pretty sure this is exactly what you want. You can even mess around with the order of the numbers (in case you want to rearrange your blog posts or pictures) and you can add more pretty easily. You even have "grid-template-areas:" which allows you to specify EXACTLY where each item will go. NO MORE HACKING FOR POSITIONSSS
Good luck out there! Please mark right if this helped.
(P.S., if you need more information on grid, one of the people that pushed for it very heavily (Rachel Andrew) made a tutorial: https://gridbyexample.com/)
This seems similar to another topic: how-create-grid-out-of-images-of-different-sizes
I fully agree with #Quibble on this.
He basically used the layout you wanted. I made a different one, it just has a different approach, though areas are the more elegant way. Just something to bear in mind, you can do it in several ways, none of which involve JS-based coding. My JSfiddle example.
.container {
display: grid;
padding: 60pt;
grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 2fr;
/* there are five values for five columns, each column gets a relative
width in relation to the grid*/
grid-template-rows: 10% 45% 35% 10%;
grid-column-gap: 10px;
grid-row-gap: 5px;
/*this means there are three rows*/
}
.container div img {
width: 100%;
height: 100%;
}
.main_1 {
grid-column: 2/5;
grid-row: 2/3;
}
.main_2 {
grid-column: 5/8;
grid-row: 2/3;
}
.main_3 {
grid-column: 8/11;
grid-row: 2/3;
}
.main_4 {
grid-column: 2/4;
grid-row: 3/4;
}
.main_5 {
grid-column: 4/7;
grid-row: 3/4;
}
.main_6 {
grid-column: 7/11;
grid-row: 3/4;
}
.footer {
grid-row: 4/5;
grid-column: 1/6;
}