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

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)

Related

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 hide various span tags with a known id leaving just one visible

I have this page where I have some span tags that works like a link, inside it I have some hidden divs, what I want to do is when I click in one of these links the div inside of the clicked one is shown and the other spans receive the property display:none.
Like this:
<style>
#divHidden{display:none;}
</style>
<span id="link_01" onclick="myfunction()"> <!--<<= when clicked-->
<div id="divHidden">Content</div> <!--<<= this comes visible-->
</span>
<span id="link_02" onclick="myfunction()"> <!--<<= then this-->
<div id="divHidden">Content</div>
</span>
<span id="link_03" onclick="myfunction()"> <!--<<= and this goes hidden-->
<div id="divHidden">Content</div>
</span>
how do I code this in javascript?
Something like this?
UPDATE: to work as request, hope this is ok
codepen version
$('.content-wrapper').on('click','.tag', function(evt){
evt.preventDefault();
var selectedDiv = $(this).prop('id');
$('.content-wrapper span:not(#' + selectedDiv + ')').hide();
$(this).find('.content').addClass('show');
})
span.tag .content {
padding-top: 10px;
text-align: center;
display: none;
}
span.tag .content.show {
display: block;
}
span.tag {
margin: 0 auto;
padding: 6px 0;
border-bottom: 1px #ddd solid;
width: 200px;
cursor: pointer;
color: #444;
height: 40px;
background: #eee;
transition: background 600ms;
display: block;
}
span.tag:hover {
background: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content-wrapper">
<span class="tag" id="tag-one">
<div class="content">Content A</div>
</span>
<span class="tag" id="tag-two">
<div class="content">Content B</div>
</span>
<span class="tag" id="tag-thre">
<div class="content">Content C</div>
</span>
</div>

Dot leaders with picture background

So I'm building a website for a restaurant and I'm in a pickle. I'm trying to create the menu there. The idea is to align the food name to the left, the price to the right and fill the gap between them with dots. Like this
Hamburger ............................................ $ 4.00
XXL Hamburger .................................... $ 4.00
Milkshake .............................................. $ 4.00
I found a couple of solutions, which only work if you have a background with one color and no texture. The idea was to fill the whole line with dots and set the name/price background span with the same color as the site background, so the dots wouldn't show. But I have a picture for the background.
I'm not going to post my code here, because it wouldn't really matter or help.
Is it even possible? Doesn't have to be css only, might as well be done with JavaScript.
I am kinda late, but you can quite easily do it with a radial-gradient:
.col {
display: inline-block;
vertical-align: top;
}
.names span {
width: 200px;
display: flex;
}
.prices span {
display: block;
text-align:right;
}
.names span:after {
content: "";
display: inline-block;
height: 1em;
flex-grow: 1;
background: radial-gradient(black 25%, transparent 25%) scroll repeat-x bottom left/5px 5px;
}
<div class='names col'>
<span>Hamburger</span>
<span>Hot Dogs</span>
<span>Superman Hamburger</span>
</div>
<div class='prices col'>
<span>$1.00</span>
<span>$0.50</span>
<span>$400.00</span>
</div>
JSFiddle Demo
It's easy to do with some simple javascript and css, here's a fiddle: jsfiddle
The key is to set the width of the div that holds the dots to the width of the column minus the width of the food name minus the width of the price, and to make sure there are more than enough dots to cover the distance, and to set overflow: hidden for the dot div.
$(".menu-row").each(function(index, element) {
var menuRowWidth = $(element).width();
var foodItemWidth = $(element).children('.food-item').width();
var priceWidth = $(element).children('.price').width();
var $dotFiller = $(element).children('.dot-filler');
var dotFillerWidth = menuRowWidth - foodItemWidth - priceWidth;
$dotFiller.width(dotFillerWidth + "px");
});
Then float the item and dot div left, the price right, all within a set width column. It's also important that overflow: hidden is set for the dots, because when we set the width of that div in javascript we want all extra dots to just be cut off. The CSS:
.food-item {
float: left
}
.dot-filler {
overflow: hidden;
width: 0;
float: left;
}
.price {
float: right;
}
.menu-row {
width: 400px;
}
Then structure your html as follows:
<div class="menu-row">
<div class="food-item">Steak</div>
<div class="dot-filler">............................................................................................</div>
<div class="price">$18.00</div>
</div>
<div class="menu-row">
<div class="food-item">Hamburger</div>
<div class="dot-filler">............................................................................................</div>
<div class="price">$8.00</div>
</div>
You can use a wrapper to set a fix width of your Name + Dots.
The css will look like this:
.wrapper {
width: 300px;
overflow: hidden;
display: inline-block;;
white-space: nowrap;
}
The HTML like this:
<div>
<ul class="noDisc">
<li>
<div class="wrapper">
<span>HAMBURGER </span>
<span>...............................................................</span>
</div>
<span>$ 40.00</span>
</li>
<li>
<div class="wrapper">
<span>FRIED CHIKEN </span>
<span>...............................................................</span>
</div>
<span>$ 13.00</span>
</li>
<li>
<div class="wrapper">
<span>STEAK ON A STICK </span>
<span>...............................................................</span>
</div>
<span>$ 99.00</span>
</li>
</ul>
</div>
Live sample:
fiddle
Use display:table; and display: table-cell; for the divs inside the list-elements and border-bottom: Xpx dotted black; for the dots.
ul{
margin: 0;
padding: 0;
}
ul li{
display: table;
width: 100%;
}
ul li div {
display: table-cell;
}
ul li div.food {
padding-right: 5px;
}
ul li div.dots {
border-bottom: 1px dotted #000;
width: 100%;
position: relative;
top: -4px;
}
ul li div.price {
padding-left: 5px;
}
<ul>
<li>
<div class="food">Spaghetti</div>
<div class="dots"> </div>
<div class="price">10.00$</div>
</li>
<li>
<div class="food">Spaghetti</div>
<div class="dots"></div>
<div class="price">10.00$</div>
</li>
<li>
<div class="food">Spaghetti</div>
<div class="dots"></div>
<div class="price">10.00$</div>
</li>
</ul>
Thanks. I used what you had here and improved on it. This code is meant for woocommerce product items, but can be edited for whatever you need. $containerElement is the element you are measuring the width of.
/**
* dotFiller
* adds dynamic dot leaders between product title and count element (<mark>)
* #return void
*/
var dotFiller = function(){
var $containerElement = $('ul.products li.product.has-children h2'),
df = '<div class="df">.....................................................................</div>';
$containerElement.each(function(i,el){
var $el = $(el),
w = $el.width(),
mw = $el.find('mark').width(),
tw = $el.find('span').width(),
dfw = (w - mw - tw) - 24;
// if its not there, lets add it
if (!$(el).has('.df').length){
$el.find('span').after(df);
}
$el.find('.df').css('width',dfw + "px");
});
};
dotFiller();
With this code, you can update/ recalculate on resize like so :
$('window').on('resize',function(){ dotFiller(); });
And here is my css for the internal elements:
mark {
background-color: transparent;
color: $secondary;
display: inline-block; float: right;
font-weight: normal;
}
div.df {
overflow: hidden;
display: inline-block;
margin-left: 10px;
position: relative;
top: 2px;
font-weight: normal;
opacity: 0.8;
}
I hope this helps someone!
Use a div that has a flex spacer with a border-bottom to achieve easy leader dots... The flex layout seems to be the most elegant solution. No pseudo-elements, or left and right block display, etc... Very simple...
HTML
<div class="list-item">
<div class="header-row">
<h4>Menu</h4>
</div>
<br>
<div class="list-item-row">
<div class="left">Hamburger</div>
<div class="dots"></div>
<div class="right">$5.00</div>
</div>
<div class="list-item-row">
<div class="left">Hamburger (XXL)</div>
<div class="dots"></div>
<div class="right">$7.50</div>
</div>
<div class="list-item-row">
<div class="left">Milkshake</div>
<div class="dots"></div>
<div class="right">$3.50</div>
</div>
<div class="list-item-row">
<div class="left">Pickle</div>
<div class="dots"></div>
<div class="right">Free</div>
</div>
</div>
CSS
#import url("https://fonts.googleapis.com/css?family=Lato|Montserrat:400,700|Roboto:400,700");
* {
margin: 0;
padding: 0;
}
button {
font-family: "Roboto";
font-size: 16px;
padding: 5px;
border-radius: 3px;
border: solid #424242 1px;
}
.list-item {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 20px;
font-family: "Lato";
background: #f0f0f0;
padding: 10px;
border: solid #e0e0e0 1px;
}
.list-item-row,
.header-row {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.left,
.right {
font-family: "Roboto";
}
.right {
color: blue;
}
}
.dots {
flex: 1 0 0;
border-bottom: dotted 2px #b0b0b0;
margin-left: 1em;
margin-right: 1em;
}
See Codepen here => https://codepen.io/anon/pen/vVZmxB

How to wrap more than one div around a div

I have a div (Slideshow) and I want to wrap around it small divs (Items). The Slideshow div will be static and the Items will be rendered automatically using a Repeater Control.
I made this image to better illustrate what I need to achieve.
I saw this Question and I thought I could use the same logic, let the Repeater items get rendered normally and then change the markup using JavaScript and use some sort of a CSS Grid layout to style the first 4 items for example on the left and the right and the rest will be beneath them but I'm not sure how to do it plus if there's a more simple solution I thought it could be cleaner than using the concept I saw in the question I referred.
Update1: Changed the picture to show the exact desired output
You could generate a Masonary layout. This plug in may be helpful, https://github.com/desandro/masonry
You could do this with bootstrap columns as well. For the first row, with the slideshow, you have 3 columns. The outer left and right columns will have 2 nested rows. http://getbootstrap.com/examples/grid/. This is what Im most familiar with so I'll show you how I would implement a solution for the first row and how to implement a second row with 4 columns.
<div class="row">
<!-- Outer Left Column -->
<div class="col-xs-4">
<div class="row">
<div class="col-xs-12">
Item
</div>
</div>
<div class="row">
<div class="col-xs-12">
Item
</div>
</div>
</div>
<div class="col-xs-12">
Slide Show
</div>
<!-- Outer Right Column -->
<div class="col-xs-4">
<div class="row">
<div class="col-xs-12">
Item
</div>
</div>
<div class="row">
<div class="col-xs-12">
Item
</div>
</div>
</div>
</div>
<!-- Row With Four Items -->
<div class="row">
<div class="col-xs-3">
Item
</div>
<div class="col-xs-3">
Item
</div>
<div class="col-xs-3">
Item
</div>
<div class="col-xs-3">
Item
</div>
</div>
Checkout the angular material layout system as well. This will be harder to implement though because it requires Angular. https://material.angularjs.org/latest/#/layout/grid
Check this solution out and see if you can adopt it to your project: http://jsfiddle.net/1b0hoked/.
HTML:
<div id = "wrapper">
<div id = "slideshow"></div>
</div>
CSS:
*, :before, :after {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
padding: 10px;
}
#wrapper {
counter-reset: item-counter;
text-align: right;
margin: 0 auto;
display: table;
outline: 1px solid gray;
position: relative;
}
#slideshow {
width: 210px;
height: 210px;
line-height: 210px;
text-align: center;
border: 2px solid red;
position: absolute;
top: 5px;
left: 50%;
margin-left: -105px;
}
#slideshow:before {
content: "Slide Show";
vertical-align: middle;
font: bold 16px/1 Sans-Serif;
color: red;
}
.item {
height: 100px;
width: 100px;
text-align: center;
line-height: 96px;
border: 2px solid #aaa;
}
.item:before {
counter-increment: item-counter;
content: "item " counter(item-counter);
vertical-align: middle;
font: bold 12px/1 Sans-Serif;
color: #aaa;
}
.item {
float: left;
margin: 5px;
}
.item:nth-of-type(4n + 1) {
clear: left;
}
.item:nth-of-type(3) {
float: right;
margin-top: -105px;
}
.item:nth-of-type(4) {
float: right;
clear: right;
margin-left: -105px;
}
.item:nth-of-type(2) {
clear: left;
}
JS/jQuery:
$(function() {
var numToAdd = 50;
while(--numToAdd >= 0) {
$("</p>").addClass("item").appendTo("#wrapper");
}
});

Centering a inline-block element

I want center a inline-block element, with a text inside.
This is the HTML:
<div class="container body">
<h1 class="title">FAÇA SUA RESERVA</h1>
<p>Escolha o dia que deseja participar e aceite o nosso aplicativo.</p>
<hr>
<div class="row">
<div class="box thursday col-xs-6 col-sm-3">
<img src="assets/images/box.png">
</div>
<div class="box friday col-xs-6 col-sm-3">
<img src="assets/images/box.png">
</div>
<div class="box friday_2 col-xs-6 col-sm-3">
<img src="assets/images/box.png">
</div>
<div class="box saturday col-xs-6 col-sm-3">
<img src="assets/images/box.png">
</div>
<div class="col-9">
</div>
</div>
I need center just the title, and the subtitle "FAÇA SUA RESERVA", for this i'm using:
.container.body .subtitle,
.container.body .title {
text-align: center;
}
It's working ok, but if i make changes in the title element, the text-align: center it stops working..
This is the css for the title element:
.title {
display: inline-block;
border: 1px solid #F98835;
color: #f98835;
padding: 10px;
}
i already try setup margin: 0 auto;, and it doesn’t seem to have an effect
You need to add text-align: center to the parent of the inline-block element that you want to center.
.container.body {
text-align: center;
}
you can style your title like so :
.title {
width:330px;
border: 1px solid #F98835;
color: #f98835;
padding: 10px;
margin: 0 auto;
}
For your code to work you should be using the normal display: block behavior. This is the default value by the way. If you set the text-align: center to regular blocks it will center the text within. So you can individually center header/subtitle content and leave the rest normal.
.container.body .subtitle,
.container.body .title {
text-align: center ;
}
.title {
display: block;
border: 1px solid #F98835;
color: #f98835;
padding: 10px;
}
If you insist on still using an inline-block you can use the solution by Steve Saunders. But since text-align is an inherited trait you will have to "undo" this by setting text-align: left on the block-item children you do not want this to apply to.
as you make your h1 tag inline-block, it looses its block element properties partially, thus the width is limited to the content it has. That's why text-align: center does not work.
So, you can insert span inside the h1 tag or any block element with .title class and use that property.
.title span {
display: inline-block;
border: 1px solid #F98835;
color: #f98835;
padding: 10px;
}
Hope this helps what you are looking for.

Categories