I'm implementing cross-window drag-and-drop for item ordering on collaborative site and I am unable to synchronize drags to the same list. I would need to detect whether I dropped an item to the same list to avoid "add", "remove" operations and use a single "move".
NOTE: this problem involves two browser windows e.g. Firefox and Chrome; unless it works in that case, it's not suitable solution. Also, I'm not looking for a server based solution.
The gist of the problem can be demonstrated by this:
function update(source, className, d){
var count = source.getElementsByClassName(className)[0];
count.innerText = parseInt(count.innerText) + d;
}
var els = document.getElementsByClassName("source");
for(var i = 0; i < els.length; i += 1){
(function(el){
el.ondragover = function(ev){
ev.dataTransfer.dropEffect = "move";
ev.preventDefault();
ev.stopPropagation();
};
el.ondrop = function(ev){
ev.preventDefault();
ev.stopPropagation();
var id = ev.dataTransfer.getData("x/source");
if(el.dataset.id == id){
update(el, "self", 1);
// how to send a value from here to dragEnd -->>
return;
}
};
})(els[i]);
}
var els = document.getElementsByClassName("element");
for(var i = 0; i < els.length; i += 1){
(function(el){
el.draggable = true;
el.ondragstart = function(ev){
grabbingFrom = el.parentNode.dataset.id;
ev.dataTransfer.effectAllowed = "all";
ev.dataTransfer.setData("x/source", el.parentNode.dataset.id);
console.log(JSON.stringify(ev.dataTransfer.getData("x/source")));
}
el.ondragend = function(ev){
var self = false; // how to get a value <--- here
if(self){
update(el, "self", 1);
}
ev.preventDefault();
}
})(els[i]);
}
.clear { clear: both; }
.source {
float: left; border: 1px solid #000; margin: 32px;
height: 100px; width: 150px;
}
.source .element { width: 32px; height: 32px; margin: 8px;
background: #AAA; margin: 8px;
line-height: 32px; text-align: center;
}
.source .element:hover {
background: hsla(0, 70%, 70%, 1);
cursor: move;
}
<div class="source" data-id="alpha" >
Alpha
<div class="self">0</div>
<div draggable="true" class="element">X</div>
</div>
<div class="source" data-id="beta" >
Beta
<div class="self">0</div>
<div draggable="true" class="element">X</div>
</div>
When you Drag from "Beta" box to a "Beta" box in cross-windows, then both "Beta" counts should be incremented. Currently only one increments. Basically how to communicate across that "Yes, I've dropped this item into a 'beta' box.". The problem boils down to sending content from ondrop event to ondragend.
I've been unable to find a suitable way to do it. Any ideas?
Or, is the answer simply that it isn't possible.
Related
I'm creating a tab menu like this:
function clear_selected() //sets all columns color black
{
var parent = document.querySelector("#container")
var items = document.querySelectorAll(".item")
var n = items.length;
for (var i = 0; i < n; i++)
items[i].style.backgroundColor = "";
}
function plus(itself) //adds another column
{
var parent = itself.parentElement;
var n = parent.childElementCount;
clear_selected();
var n = parent.querySelectorAll(".item").length;
var page = document.createElement("button");
page.className = "item";
page.style.backgroundColor = "blue";
page.textContent = "column"
page.onclick = function() {
clear_selected();
this.style.backgroundColor = "blue";
};
var temp = document.createElement("span");
temp.className = "del"
temp.innerHTML = "×"
temp.onclick = function() { //it's suppose to remove a column and color default as blue
document.querySelector("#main_item").style.backgroundColor = "blue" //THIS LINE ISN'T WORKING
this.parentElement.remove();
};
page.appendChild(temp);
parent.insertBefore(page, parent.childNodes[n]);
}
function see(el) {
clear_selected();
el.style.backgroundColor = "blue";
}
#container {
display: flex;
width: 100%;
height: 50px;
text-align: center;
background-color: yellow;
}
.item {
background-color: black;
color: white;
border: none;
outline: none;
cursor: pointer;
margin: 0.1rem;
padding: 0.1rem;
max-width: 100%;
}
.del {
background-color: red;
display: inline-block;
cursor: pointer;
border-radius: 50%;
width: 0.7rem;
margin-left: 2rem;
}
<div id="container">
<button class="item" id="main_item" style="background-color:blue;" onclick="see(this)">default column </button>
<button class="item" onclick="plus(this)">+</button>
</div>
but when I press the 'x' to remove a column, I want the default column to color blue, but the line of code which is suppose to achieve that isn't working
document.querySelector("#main_item").style.backgroundColor = "blue"
Before pressing 'x':
After pressing 'x' on the last column:
What it SHOULD look like:
I've losing sleep over this, can someone PLEASE tell me why isn't it working?
When you click on the "X", both of your onclick handlers are getting called, including the one that runs clear_selected, which sets the background color to "".
You can fix this by using stopPropagation on the event passed into the onclick function for the "x". That will stop the click event from going up the chain to the parent element of the "x".
temp.onclick = function(e) {
document.querySelector("#main_item").style.backgroundColor = "blue"
this.parentElement.remove();
e.stopPropagation();
};
I have code written to allow an HTML element to be dragged after the mouse has been down over that element for a certain period of time.
The problem is that when I am using native HTML drag and drop, and I enable the draggable property when this timeout is up (the mouse has been down on that element for that period of time), if the mouse had been moved while it was down before that timeout was up, HTML will not trigger a dragstart event or even start dragging the element.
There is an example below.
var t;
function startDelayedDrag() {
clearTimeout(t);
document.getElementById('dragtarget').draggable = false;
console.log('mousedown')
t = setTimeout(function() {
console.log('dragging enabled')
document.getElementById('dragtarget').draggable = true;
}, 1000);
}
.droptarget {
float: left;
width: 100px;
height: 35px;
margin: 15px;
padding: 10px;
border: 1px solid #aaaaaa;
user-select: none;
}
<div class="droptarget">
<p onmousedown="startDelayedDrag()" id="dragtarget">Drag me!</p>
</div>
<div class="droptarget"></div>
This one is tricky and it might be different from what you had in mind, but here is goes an idea how to solve your issue:
Start the drag event
Hide the drag object by setting an image using setDragImage
Clone the drag element node, hide the clone and add it to the document (since it's not possible to change the image set by setDragImage)
Start the timeout to change the visibility of the ghost element
This could be yet improved in many ways, but I think you can get the mechanics of how it works as it is. As a reference see the following snippet:
const [$drag] = document.getElementsByClassName('drag')
const [$pixel] = document.getElementsByClassName('pixel')
let $ghost = null
$drag.addEventListener("dragstart", e => {
// set the current draged element invisible
e.dataTransfer.setDragImage($pixel, 0, 0)
// create a ghost element
$ghost = $drag.cloneNode(true)
$ghost.style.position = "absolute"
$ghost.style.display = "none"
document.body.appendChild($ghost)
setTimeout(() => {
$ghost.style.display = 'block'
}, 1000)
})
$drag.addEventListener("drag", e => {
// keep the ghost position to follow the mouse while dragging
$ghost.style.left = `${e.clientX}px`
$ghost.style.top = `${e.clientY}px`
}, false);
$drag.addEventListener("dragend", e => {
// remove the ghost
if ($ghost.parentNode) $ghost.parentNode.removeChild($ghost)
}, false)
.content {
display: flex;
}
.box {
width: 100px;
height: 35px;
padding: 10px;
margin: 10px;
border: 1px solid #aaaaaa;
}
.drop {
user-select: none;
}
.drag {
text-align: center;
}
.pixel {
width: 1px;
height: 1px;
background-color: white;
}
<div class="content">
<div draggable="true" class="drag box">Drag</div>
<div class="drop box"></div>
<div class="pixel"></div>
</div>
Update 10/4/18: I've updated the Snippet to reflected changes for anyone who may stumble upon this thread in seek of help. Existing check-boxes and newly added check-boxes will open/close the menu.
var statusChangeMenu, activeList, itemCheckBox, activeItems;
statusChangeMenu = document.getElementById("status-change-menu");
activeList = document.getElementById("active-items");
itemCheckBox = activeList.getElementsByClassName("item-checkbox");
activeItems = activeList.getElementsByClassName("active-item-text");
function addNewItem(event) {
event.preventDefault();
activeList.insertAdjacentHTML("afterbegin", "\
<li class=\"item\">\
<input class=\"item-checkbox\" type=\"checkbox\" name=\"checkbox\" />\
<span class=\"active-item-text\"></span>\
<button class=\"btn-complete\">complete</button>\
</li>");
activeItems[0].textContent = document.getElementById("new-item-text").value;
}
document.getElementById("btn-add-item").addEventListener("click", addNewItem, false);
activeList.addEventListener("change", function() {
var i, len;
for (i = 0, len = itemCheckBox.length; i < len || (i = 0); ++i) {
if (itemCheckBox[i].checked) {
i = 40;
break;
}
}
statusChangeMenu.style.height = i + "px";
}, false);
*{
margin: 0;
padding: 0;
}
body{
background-color: #393F4D;
}
header{
background-color: #1D1E22;
color: #FEDA6A;
text-align: center;
font-size: 10px;
}
main{
background-color: #707070;
max-width: 700px;
margin: auto;
margin-top: 20px;
padding: 15px;
}
#status-change-menu{
background-color: rgb(218, 123, 123);
margin-top: 10px;
height: 0px;
overflow: hidden;
transition: all .25s ease-in-out;
}
#status-change-menu>button>img{
height: 40px;
}
form{
background-color: #D4D4DC;
padding: 10px;
text-align: right;
box-shadow: 1px 1px 3px;
}
#new-item-text{
width: 100%;
}
#btn-add-item{
padding: 5px;
box-shadow: 1px 1px 3px;
}
.item-list-container{
background-color: #D4D4DC;
margin-top: 20px;
box-shadow: 1px 1px 3px;
}
.item{
background-color: rgb(165, 233, 222);
list-style: none;
display: grid;
grid-template-columns: auto 1fr max-content;
grid-template-rows: 30px;
margin-top: 10px;
}
.item-checkbox{
grid-column: 1/2;
width: 30px;
margin:auto;
}
.active-item-text{
grid-column: 2/3;
background: rgb(252, 252, 252);
overflow: hidden;
}
.btn-complete{
grid-column: 3/4;
}
.item>input{
height: 20px;
}
<body id="the-list">
<header>
<h1>The List V4</h1>
</header>
<main>
<form action="#">
<textarea name="textbox" id="new-item-text" cols="30" rows="1"></textarea>
<button type="submit" id="btn-add-item">Add</button>
</form>
<div id="status-change-menu" class="change-menu">
<h3>Status Change Menu</h3>
<button class="btn-bar-hold">BTN1<img src="img/btn_hold.svg" alt=""></button>
<button class="btn-bar-delete">BTN2<img src="img/btn_delete.svg" alt=""></button>
</div>
<div class="item-list-container">
<ul id="active-items" class="item-list">
<li class="item">
<input class="item-checkbox" type="checkbox" name="checkbox">
<span class="active-item-text">random text text random</span>
<button class="btn-complete">complete</button>
</li>
<li class="item">
<input class="item-checkbox" type="checkbox" name="checkbox">
<span class="active-item-text">random text text random</span>
<button class="btn-complete">complete</button>
</li>
</ul>
</div>
</main>
</body>
I'm working on a simple checklist web app using pure vanilla HTML, CSS, javascript. I've been stuck in one part all weekend. Hoping someone can shed some light on what I'm missing or doing wrong. Here's where I'm at.
My Goal
Whenever an item in the checklist (ul) is selected (via checkbox), a hidden menu slides out with various options to manipulate the selected item(s). The menu must stay visible if any of the checkboxes on the list are checked. The menu must close if no checkboxes are checked.
Where I'm Stuck
I'm able to get the menu to slide out during a 'change' event of the checkbox, but I can't get the menu element to react after the initial change event. During debugging, it also appears the menu element is not reacting to the checkbox is in a 'checked' state, but simply just reacting to the checkbox being changed in general. Here's the JS code I have, but I've tested various other configurations with no success.
Code Pen with Full Code & Snippet of related JS code below.
Updated Codepen 10/4/18
https://codepen.io/skazx/pen/mzeoEO?
var itemCheckBox = document.querySelectorAll('input[type="checkbox"]')
var statusChangeMenu = document.getElementById("status-change-menu")
for(var i = 0 ; i < itemCheckBox.length; i++){
itemCheckBox[i].addEventListener("change", function(){
if (!itemCheckBox.checked)
{statusChangeMenu.style.height = "40px";}
else
{statusChangeMenu.style.height = "0px";}
})}
I've read a few dozen different post and articles, but most were related to only having 1 checkbox or used jquery. Let me know if you need any further details. Thank you!
itemCheckBox refers to a NodeList returned by querySelectorAll, not an individual element, so saying itemCheckBox.checked doesn't really make sense.
You should be checking if any checkbox in the list is checked, which you can use with the .some() function, like so:
Here's a working demo
for (var i = 0; i < itemCheckBox.length; i++) {
itemCheckBox[i].addEventListener("change", function(event) {
if (!event.target.checked) {
statusChangeMenu.style.height = "40px";
} else {
statusChangeMenu.style.height = "0px";
}
});
}
var itemCheckBox = document.querySelectorAll('input[type="checkbox"]');
var statusChangeMenu = document.getElementById("status-change-menu");
function changeHandler (event) {
// get the list of checkboxes in real time in case any were added to the DOM
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
var anyChecked = [].some.call(checkboxes, function(checkbox) { return checkbox.checked; });
// alternatively (instead of using .some()):
// var anyChecked = false;
// checkboxes.forEach(function (checkbox) {
// if (checkbox.checked) {
// anyChecked = true;
// }
// });
if (anyChecked) {
statusChangeMenu.style.height = "40px";
} else {
statusChangeMenu.style.height = "0px";
}
}
for (var i = 0; i < itemCheckBox.length; i++) {
itemCheckBox[i].addEventListener("change", changeHandler);
}
for (var i = itemCheckBox.length; i < itemCheckBox.length + 2; i++) {
// add some checkboxes dynamically
var newCheckbox = document.createElement("input");
var newLabel = document.createElement("label");
newLabel.innerText = "Checkbox " + (i + 1);
newCheckbox.type = "checkbox";
// -- IMPORTANT-- bind event listener on dynamically added checkbox
newCheckbox.addEventListener("change", changeHandler);
newLabel.appendChild(newCheckbox);
newLabel.appendChild(document.createElement("br"));
document.body.appendChild(newLabel);
}
#status-change-menu {
height: 0;
background-color: red;
overflow: hidden;
color: white;
font-weight: bold;
}
<div id="status-change-menu">I should be visible if any checkboxes are checked</div>
<label>Checkbox 1<input type="checkbox"/></label><br/>
<label>Checkbox 2<input type="checkbox"/></label><br/>
<label>Checkbox 3<input type="checkbox"/></label><br/>
mhodges is correct in that itemCheckBox is a NodeList, not an individual element. Another issue is that you are trying to test if the box that changed is checked, and if it isn't, you are closing the menu. As you described, that is not what you want.
You need another way to check to see if all check boxes are unchecked before you close the menu. A simple way to do that is just another inner loop in the onChange function:
for(var i = 0 ; i < itemCheckBox.length; i++){
itemCheckBox[i].addEventListener("change", function(){
showMenu = false
for(var j = 0; j < itemCheckBox.length; j++)
{
if(itemCheckBox[j].checked)
showMenu = true
}
if (showMenu)
{statusChangeMenu.style.height = "40px";}
else
{statusChangeMenu.style.height = "0px";}
})}
Heres a modified Snippet
I'm trying to have a bgcolor change for an element on mouseover, mouseout, and onclick. The problem is Javascript overwrites my onclick with mouseout, so I can't have both. So is there any way to have mouseover reset after mouseout?
function init() {
document.getElementById('default').onmouseover = function() {
tabHoverOn('default', 'grey')
};
document.getElementById('default').onmouseout = function() {
tabHoverOff('default', 'yellow')
};
document.getElementById('section2').onmouseover = function() {
tabHoverOn('section2', 'grey')
};
document.getElementById('section2').onmouseout = function() {
tabHoverOff('section2', 'yellow')
};
document.getElementById('section3').onmouseover = function() {
tabHoverOn('section3', 'grey')
};
document.getElementById('section3').onmouseout = function() {
tabHoverOff('section3', 'yellow')
};
}
function tabHoverOn(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
function tabHoverOff(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
var current = document.getElementById('default');
function tab1Highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab1highlight";
current = id;
}
function tab2highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab2highlight";
current = id;
}
function tab3highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab3highlight";
current = id;
}
window.onload = init();
body {
width: 900px;
margin: 10px auto;
}
nav {
display: block;
width: 80%;
margin: 0 auto;
}
nav > ul {
list-style: none;
}
nav > ul > li {
display: inline-block;
margin: 0 3px;
width: 150px;
}
nav > ul > li > a {
width: 100%;
background-color: #ffff66;
border: 1px solid #9b9b9b;
border-radius: 12px 8px 0 0;
padding: 8px 15px;
text-decoration: none;
font-weight: bold;
font-family: arial, sans-serif;
}
main {
display: block;
width: 80%;
margin: 0 auto;
border: 1px solid #9b9b9b;
padding: 10px;
}
main > h1 {
font-size: 1.5em;
}
.tab1highlight {
background-color: #339966;
color: white;
}
.tab2highlight {
background-color: #ff6666;
color: white;
}
.tab3highlight {
background-color: #6600ff;
color: white;
}
main img {
border: 5px solid #eeefff;
width: 80%;
margin-top: 20px;
}
<body>
<nav>
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</nav>
<main>
<h1>Exercise: Navigation Tab #5</h1>
<ul>
<li>
Combine the navigation tab exercises #1, #3, and #4 in one file, including <br>
<ul>
<li>temporarily change the background color of a tab when the cursor is hovering on it.</li>
<li>set the foreground and background color of the tab being clicked.</li>
<li>change the background color of the main element based on the selected tab.</li>
</ul>
<p>
To test, click on a tab and then move your mouse around. For example, the third tab is clicked, the tab background color is switched to blue. Then hover the mouse over the third tab, the background color of the tab should be switch to light green and then back to blue after the mouse moves out.
</p>
<img src="menu_tab5.jpg">
</li>
</ul>
</main>
It's generally a good idea to keep CSS out of JavaScript completely if you can help it. A better strategy for solving the hover problem is to use the CSS pseudo selector :hover rather than coding the color changes in JavaScript. If you give all your tabs the same class, you only have to write the CSS once:
.tab {
background-color: yellow;
}
.tab:hover {
background-color: grey;
}
Once you've done that, you can also relegate the click styling to CSS by creating an event handler that adds and removes a special class each time a tab is clicked.
In the CSS file:
.tab.clicked {
background-color: blue;
}
And then in JavaScript, something like:
var tabs = document.getElementsByClassName('tab');
for (i = 0; i < tabs.length; i ++) {
tabs[i].onclick = function (ev) {
for (i = 0; i < tabs.length; i ++) {
tabs[i].classList.remove('clicked');
}
ev.currentTarget.classList.add('clicked');
};
}
I've created a JSFiddle to illustrate.
Try updating a Boolean variable.
var Ele = document.getElementById('default');
var clicked = false;
Ele.onclick = function(){
clicked = true;
// add additional functionality here
}
Ele.onmouseover = function(){
clicked = false;
// add additional functionality here
}
Ele.onmouseout = function(){
if(!clicked){
// add additional functionality here
}
}
I want to use JavaScript to check if one div element (that can be dragged) is touching another div element.
Here is some code:
<div id="draggable" style="position: absolute; top: 100px; left: 200px; background-color: red; width: 100px; height: 100px;"></div>
<div style="background-color: green; width: 100px; height: 100px;"></div>
Can this be done?
If so, how?
Edit: I do not want to use jQuery, just plain old JavaScript!
A plain old JS solution
Below is a "plain old JavaScript" rewrite of the overlap detection function found in this answer to the question titled "jQuery/Javascript collision detection".
The only real difference between the two is the replacement of the use of jQuery to get element position and width for calculating the bounding box.
Native JavaScript makes this task easy via the Element.getBoundingClientRect() method, which returns the four values needed to create the position matrix returned by the getPositions function.
I added a click handler for the boxes as a simple demonstration of how you might use the function to compare a target (clicked, dragged, etc.) element to a set of selected elements.
var boxes = document.querySelectorAll('.box');
boxes.forEach(function (el) {
if (el.addEventListener) {
el.addEventListener('click', clickHandler);
} else {
el.attachEvent('onclick', clickHandler);
}
})
var detectOverlap = (function () {
function getPositions(elem) {
var pos = elem.getBoundingClientRect();
return [[pos.left, pos.right], [pos.top, pos.bottom]];
}
function comparePositions(p1, p2) {
var r1, r2;
if (p1[0] < p2[0]) {
r1 = p1;
r2 = p2;
} else {
r1 = p2;
r2 = p1;
}
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
function clickHandler(e) {
var elem = e.target,
elems = document.querySelectorAll('.box'),
elemList = Array.prototype.slice.call(elems),
within = elemList.indexOf(elem),
touching = [];
if (within !== -1) {
elemList.splice(within, 1);
}
for (var i = 0; i < elemList.length; i++) {
if (detectOverlap(elem, elemList[i])) {
touching.push(elemList[i].id);
}
}
if (touching.length) {
console.log(elem.id + ' touches ' + touching.join(' and ') + '.');
alert(elem.id + ' touches ' + touching.join(' and ') + '.');
} else {
console.log(elem.id + ' touches nothing.');
alert(elem.id + ' touches nothing.');
}
}
#box1 {
background-color: LightSeaGreen;
}
#box2 {
top: 25px;
left: -25px;
background-color: SandyBrown;
}
#box3 {
left: -50px;
background-color: SkyBlue;
}
#box4 {
background-color: SlateGray;
}
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
color: White;
font: bold 72px sans-serif;
line-height: 100px;
text-align: center;
cursor: pointer;
}
.box:hover {
color: Black;
}
<p>Click a box to see which other boxes are detected as touching it.<br />
<em>If no alert dialog box appears, open your console to view messages.</em></p>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
<div class="box" id="box4">4</div>
Update: I realize now that this only accounts for the intersection of the top left corner of the target element and therefore, doesn't provide a complete solution. But I'll leave it up for posterity in case someone finds it useful for other purposes.
Use element.getBoundingClientRect() and document.elementFromPoint()
You can use element.getClientBoundingRect() (src) to get the position of the target (clicked, dragged, etc.) element.
Temporarily hide the target element, then use document.elementFromPoint(x, y) (src) to get the top-most element at that position, and then check it's class name for comparison (you could compare any attribute or property instead, if you prefer).
To achieve cross-browser compatible behavior from this method
read: document.elementFromPoint – a jQuery solution (You don't
have to use jQuery to achieve this result. The method can be
replicated in pure JS.)
Addendum:
I am only showing the function for detecting overlap instead of showing drag-and-drop or drag-to-move functionality because it isn't clear which of those, if either, you are trying to implement and there are other answers showing how to accomplish various drag patterns.
In any case, you can use the detectCollision() function below in combination with any drag solution.
var box2 = document.getElementById('box2'),
box3 = document.getElementById('box3');
box2.onclick = detectCollision;
box3.onclick = detectCollision;
function detectCollision(e) {
var elem = e.target,
elemOffset = elem.getBoundingClientRect(),
elemDisplay = elem.style.display;
// Temporarily hide element
elem.style.display = 'none';
// Check for top-most element at position
var topElem = document.elementFromPoint(elemOffset.left, elemOffset.top);
// Reset element's initial display value.
elem.style.display = elemDisplay;
// If a top-most element is another box
if (topElem.className.match(/box/)) {
alert(elem.id + " is touching " + topElem.id);
} else {
alert(elem.id + " isn't touching another box.");
};
}
#box1 {
background-color: LightSeaGreen;
}
#box2 {
top: 25px;
left: -25px;
background-color: SandyBrown;
}
#box3 {
background-color: SkyBlue;
}
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
}
.clickable {
cursor: pointer;
}
<div class="box" id="box1"></div>
<div class="box clickable" id="box2"></div>
<div class="box clickable" id="box3"></div>