web-dev-qa-db-fra.com

Redimensionner dynamiquement les colonnes dans la disposition de grille css avec la souris

J'essaie de redimensionner dynamiquement les boîtes de disposition de grille css en faisant glisser les séparateurs de colonne (ou les espaces réservés de redimensionnement) avec la souris.

J'ai défini resize: horizontal; sur l'élément nav pour le redimensionner. Il est redimensionné lorsque je déplace la petite poignée de redimensionnement dans le coin inférieur droit de l'élément, mais la largeur de la colonne voisine n'est pas ajustée automatiquement, ce qui entraîne un chevauchement. Voici un codepen cassé.

HTML:

<main>
 <nav>#1</nav>
 <header>#2</header>
 <section>#3</section>
</main>

CSS:

main {
    display: grid;
    border: 3px dotted red;
    grid-gap: 3px;
    grid-template-columns: 200px 1fr;
    grid-template-rows: 100px 1fr;
    height: 100%;
}

nav {
    grid-column: 1;
    grid-row: 1;
    grid-row: 1 / span 2;
    resize: horizontal;
    overflow: scroll;
    border: 3px dotted blue;
}

Je m'attendais à ce que le moteur de grille css gère automatiquement ce cas, mais apparemment, ce n'est pas le cas.

J'ai expérimenté avec jquery-ui redimensionnable mais cela ne semble pas bien fonctionner avec les grilles CSS.

Je cherche comment le faire avec jquery en définissant l'attribut de grille grid-template-columns/rows: sur une valeur dynamique, mais il est difficile de savoir comment intercepter les événements générés en redimensionnant l'élément via la poignée de redimensionnement. L'événement jquery resize n'est déclenché que sur l'objet window et non sur les éléments dom.

Quel pourrait être un moyen de le faire sans avoir à gérer des événements de souris de bas niveau tels que dragstart/dragend?

5
ccpizza

Ce que vous cherchez à réaliser est possible en utilisant uniquement des CSS. J'ai modifié votre exemple. Les principaux plats à emporter sont les suivants:

  1. Plus important encore, essayez de ne pas insérer de contenu brut dans vos balises de mise en page sémantique. Utilisez des balises d'en-tête, de paragraphe et de liste plutôt que des balises text et br. Cela rend votre code à la fois plus facile à lire et à raisonner. Un grand nombre de vos problèmes sont dus à la manière dont la refusion est gérée dans les zones de grille.
  2. Utilisez grid-template pour simplifier votre mise en page, car cela facilitera ultérieurement la fusion des points d'arrêt.
  3. Utiliser le débordement: auto; en spécifiant redimensionner: vertical/horizontal. Sans paramétrage de débordement, le redimensionnement échouera.
  4. Utilisez les valeurs min/max largeur/hauteur pour créer des limites pour le redimensionnement.

body {
    margin: 10px;
    height: 100%;
}

main {
    display: grid;
    border: 3px dotted red;
    padding: 3px;
    grid-gap: 3px;
    
    grid-template: 
    "nav head" min-content
    "nav main" 1fr
        / min-content 1fr;
}

nav {
    grid-area: nav;
    border: 3px dotted blue;
    overflow: auto;
    resize: horizontal;
    
    min-width: 120px;
    max-width: 50vw;
}

header {
    grid-area: head;
    border: 3px dotted orange;
    overflow: auto;
    resize: vertical;
    
    min-height: min-content;
    max-height: 200px;
}

section {
    grid-area: main;
    border: 3px dotted gray;
}
<main>
  <nav>
    <ul>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
    </ul>
  </nav>

  <header>
    <h1>Header Title</h1>
    <small>Header Subtitle</small>
  </header>

  <section>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </section>
</main>

2
baetheus

La solution consiste à pas utiliser une taille de colonne fixe explicite (grid-template-columns: 200px 1fr;) mais plutôt des tailles de colonne relatives telles que grid-template-columns: 0.2fr 1fr; - le moteur CSS de la grille gérera le redimensionnement des zones adjacentes. La prochaine chose à faire est d’ajouter des div imbriquées dans les cases de la grille, de régler leur hauteur/largeur minimales à 100% et de les redimensionner via jqueryui redimensionnable

Le jsfiddle } corrigé.

/* Javscript */

$('.left_inner').resizable();
$('.right_top_inner').resizable();
$('.right_bottom_inner').resizable();
/* CSS */

	.grid {
		display: grid;
		grid-template-columns: 0.2fr 1fr;
		grid-template-rows: 1fr 4fr;
        grid-gap: 3px;
		position: relative;
	}

	.left {
		grid-row: 1 / span 2;
	}

	.right_top {
		grid-column: 2;
		grid-row: 1;
	}

	.right_bottom {
		grid-column: 2;
		grid-row: 2;
	}

	.left_inner {
		background-color: #fedcd2;
		padding: 0;
		width: 100%;
		min-width: 100%;
		height: 100%;
		min-height: 100%;
		text-align: center;
	}

	.right_top_inner {
		background-color: #f9cf00;
		padding: 0;
		width: 100%;
		min-width: 100%;
		height: 100%;
		min-height: 100%;
		text-align: center;
	}

	.right_bottom_inner {
		background-color: #f8eee7;
		padding: 0;
		width: 100%;
		min-width: 100%;
		height: 100%;
		min-height: 100%;
		text-align: center;
	}
<!-- HTML -->

<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>

	<main class="grid">
	 <aside class='left'>
	  <div class="left_inner">
		drag the bottom right handle to resize
	  </div>
	 </aside>
	 <section class="right_top">
	  <div class="right_top_inner">right_top_inner</div>
	 </section>
	 <section class="right_bottom">
	  <div class="right_bottom_inner">right_bottom_inner</div>
	 </section>
	</main>

❗️ Bien que cela fonctionne dans le scénario le plus simple possible, cela devient problématique dans un cas d'utilisation réel. J'ai essayé jquery-ui layout qui fonctionnait un peu mieux (voici un démo ), mais la lib est obsolète et glitchy avec les cadres, donc j'ai finalement opté pour angulaire- split-pane } (basé sur la valeur angulaire 1) qui fonctionne bien et est de taille plus petite.

3
ccpizza