JSFiddle - React, Tailwind, and code Playground
HTML
<div class="board">
<div id="window1" class="window">
<div class="window-background"></div>
<div class="window-content">
<div class="window-header">Window 1</div>
<p>Lorem ipsum</p>
<button type="button">Action</button>
</div>
</div>
<div id="window2" class="window">
<div class="window-background"></div>
<div class="window-content">
<div class="window-header">Window 2</div>
<p>Lorem ipsum</p>
<button type="button">Action</button>
</div>
</div>
<div>
CSS
body {
margin: 0;
}
.board {
position: relative; /* orgine pour la position absolue des .window */
height: 100vh; /* dimensions du conteneur = dimensions de l'écran */
overflow: hidden; /* pas de scroll sur le conteneur principal (pour rester simple) */
background-image: linear-gradient(to right bottom, #051937, #004d7a, #008793, #00bf72, #a8eb12); /* un "joli" gradient pour le fond */
}
.window {
position: absolute; /* position absolue pour le drag */
overflow: hidden; /* le faux fond ne doit pas dépasser de la fenêtre (voir .window-background) */
width: 200px;
height: 200px;
border: solid 1px white;
}
.window.active {
/*
la classe .active est ajoutée sur la fenêtre en js lorsqu'on clique sur la fenêtre
*/
z-index: 10; /* on passe la fenêtre active au premier plan */
border: solid 1px red;
}
.window-background {
/*
L'astuce commence ici : on ajoute un div qui fait office de fond à la fenêtre en appliquant le
même gradient que le conteneur principal. Pour que l'image de fond de la fenêtre s'affiche
comme l'image de fond du conteneur, on lui applique les mêmes dimensions (les dimensions de
l'écran dans cet exemple).
Il faut ajouter un overflow: hidden; sur la fenêtre .window pour que l'image de fond de la
fenêtre (qui fait donc la taille de l'écran) ne dépasse pas de la fenêtre.
On peut ensuite modifier la propriété background-position pour "déplacer" l'image de fond de
la fenêtre en fonction de sa position afin qu'elle corresponde à l'image de fond du conteneur.
*/
position: absolute;
width: 100vw;
height: 100vh;
background-image: linear-gradient(to right bottom, #051937, #004d7a, #008793, #00bf72, #a8eb12);
}
.window-content {
z-index: 1; /* pour placer le contenu de la fenêtre au dessus du faux fond .window-background */
position: relative; /* position requise pour utiliser z-index */
min-height: 100%; /* hauteur contenu fenêtre = hauteur fenêtre */
background-color: rgba(255, 255, 255,...
JavaScript
// voir https://www.w3schools.com/howto/howto_js_draggable.asp
dragElement(document.getElementById("window1"));
dragElement(document.getElementById("window2"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
document.querySelector('#' + elmnt.id + ' .window-header').onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
// récupération du fond de la fenêtre en cours de déplacement
windowBackground = document.querySelector('#' + elmnt.id + ' .window-background');
// modifie la propriété css background-position en fonction de la position de la fenêtre (mettre en commentaire la ligne suivante pour voir le résultat sans cette mise à jour de la position)
windowBackground.style.backgroundPosition = (pos1 - elmnt.offsetLeft) + "px " + (pos2 - elmnt.offsetTop) + "px ";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
// ajout d'une classe active sur la dernière fenêtre cliquée
document.querySelectorAll('.window').forEach(windowElement => {
windowElement.addEventListener('mousedown', e => {
document.querySelectorAll('.window.active').forEach(w => { w.classList.remove('active'); });
windowElement.classList.add('active');
});
});