web-dev-qa-db-fra.com

Meilleure façon de faire un volet divisé en html

Est-ce que quelqu'un connaît une bonne technique pour faire un volet divisé redimensionnable en HTML?

Peut-on utiliser css/jquery/javascript ou quelqu'un connaît-il une bonne bibliothèque javascript qu'ils ont utilisée?

(Un exemple de volet divisé est la barre de favoris dans Internet Explorer que vous avez peut-être ancrée à gauche de la fenêtre de votre navigateur principal)

46
mortb

Il y a sûrement beaucoup d'implémentations déjà. Heres one: http://layout.jquery-dev.com/ démontré ici: http://layout.jquery-dev.com/demos/simple.html Et le code source ici: https://github.com/allpro/layout/

36
Supr

Je voulais une version légère de Vanilla (jQuery UI Layout pèse 185 ko), aucune option de dépendance (toutes les bibliothèques existantes nécessitent jQuery). J'ai donc écrit Split.js .

Il pèse moins de 2 Ko et ne nécessite aucun balisage spécial. Il prend en charge les anciens navigateurs vers IE9 (ou IE8 avec polyfill). Pour les navigateurs modernes, vous pouvez l'utiliser avec les dispositions Flexbox et Grid.

74
nathancahill

Voici mon approche légère de Vanilla js, en utilisant flexbox:

http://codepen.io/lingtalfi/pen/zoNeJp

Testé avec succès en chrome 54, Firefox 50, Safari 10, je ne connais pas les autres navigateurs.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.rawgit.com/lingtalfi/simpledrag/master/simpledrag.js"></script>

    <style type="text/css">

        html, body {
            height: 100%;
        }

        .panes-container {
            display: flex;
            width: 100%;
            overflow: hidden;
        }

        .left-pane {
            width: 18%;
            background: #ccc;
        }

        .panes-separator {
            width: 2%;
            background: red;
            position: relative;
            cursor: col-resize;
        }

        .right-pane {
            flex: auto;
            background: #eee;
        }

        .panes-container,
        .panes-separator,
        .left-pane,
        .right-pane {
            margin: 0;
            padding: 0;
            height: 100%;
        }

    </style>

</head>

<body>

<div class="panes-container">
    <div class="left-pane" id="left-pane">
        <p>I'm the left pane</p>
        <ul>
            <li><a href="#">Item 1</a></li>
            <li><a href="#">Item 2</a></li>
            <li><a href="#">Item 3</a></li>
        </ul>
    </div>
    <div class="panes-separator" id="panes-separator"></div>
    <div class="right-pane" id="right-pane">
        <p>And I'm the right pane</p>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit. A accusantium at cum cupiditate dolorum, eius eum
            eveniet facilis illum maiores molestiae necessitatibus optio possimus sequi sunt, vel voluptate. Asperiores,
            voluptate!
        </p>
    </div>
</div>


<script>


    var leftPane = document.getElementById('left-pane');
    var rightPane = document.getElementById('right-pane');
    var paneSep = document.getElementById('panes-separator');

    // The script below constrains the target to move horizontally between a left and a right virtual boundaries.
    // - the left limit is positioned at 10% of the screen width
    // - the right limit is positioned at 90% of the screen width
    var leftLimit = 10;
    var rightLimit = 90;


    paneSep.sdrag(function (el, pageX, startX, pageY, startY, fix) {

        fix.skipX = true;

        if (pageX < window.innerWidth * leftLimit / 100) {
            pageX = window.innerWidth * leftLimit / 100;
            fix.pageX = pageX;
        }
        if (pageX > window.innerWidth * rightLimit / 100) {
            pageX = window.innerWidth * rightLimit / 100;
            fix.pageX = pageX;
        }

        var cur = pageX / window.innerWidth * 100;
        if (cur < 0) {
            cur = 0;
        }
        if (cur > window.innerWidth) {
            cur = window.innerWidth;
        }


        var right = (100-cur-2);
        leftPane.style.width = cur + '%';
        rightPane.style.width = right + '%';

    }, null, 'horizontal');


</script>

</body>
</html>

Ce code html dépend de la bibliothèque légère simpledrag Vanilla js (moins de 60 lignes de code).

10
ling

Auparavant, vous utilisiez des cadres pour y parvenir. Il y a plusieurs raisons pour lesquelles cette approche n'est pas si bonne. Voir la réponse de Reece à pourquoi les cadres sont mauvais . Voir aussi Jakob Nielson/ Pourquoi Frames Suck (la plupart du temps)

Une approche un peu plus récente consiste à utiliser des cadres en ligne. Cela a aussi des avantages et des inconvénients: Les iframes sont-ils considérés comme des "mauvaises pratiques"?

Une approche encore meilleure consiste à utiliser positionnement fixe. En plaçant le contenu de navigation (par exemple, les liens des favoris dans votre exemple) dans un élément de bloc (comme un div), appliquez position:fixed à cet élément et définissez les propriétés left, top et bottom comme ceci:

#myNav {
    position:fixed;
    left:0px;
    top:0px;
    bottom:0px;
    width:200px;
}

... vous obtiendrez une colonne verticale sur le côté gauche de la page qui ne bougera pas lorsque l'utilisateur fera défiler la page. 

Le reste du contenu de la page ne "sentira" pas la présence de cet élément de navigation, il doit donc prendre en compte les 200 pixels d'espace qu'il occupe. Vous pouvez le faire en plaçant le reste du contenu dans une autre div et en paramétrant margin-left:200px;.

6
Faust

Améliorer la réponse de Reza:

  • empêcher le navigateur d'interférer avec le glisser
  • éviter de mettre l'élément à une taille négative
  • éviter que le glissement ne se désynchronise avec la souris en raison de l'interaction incrémentielle delta avec la saturation en largeur
<html><head><style>

.splitter {
    width: 100%;
    height: 100px;
    display: flex;
}

#separator {
    cursor: col-resize;
    background-color: #aaa;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    width: 10px;
    height: 100%;

/* prevent browser's built-in drag from interfering */
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

#first {
    background-color: #dde;
    width: 20%;
    height: 100%;
    min-width: 10px;
}

#second {
    background-color: #eee;
    width: 80%;
    height: 100%;
    min-width: 10px;
}

</style></head><body>

<div class="splitter">
        <div id="first"></div>
        <div id="separator" ></div>
        <div id="second" ></div>
</div>

<script>

// function is used for dragging and moving
function dragElement( element, direction)
{
    var   md; // remember mouse down info
    const first  = document.getElementById("first");
    const second = document.getElementById("second");
    
    element.onmousedown = onMouseDown;
    
    function onMouseDown( e )
    {
        //console.log("mouse down: " + e.clientX);
        md = {e,
              offsetLeft:  element.offsetLeft,
              offsetTop:   element.offsetTop,
              firstWidth:  first.offsetWidth,
              secondWidth: second.offsetWidth};
        document.onmousemove = onMouseMove;
        document.onmouseup = () => { 
            //console.log("mouse up");
            document.onmousemove = document.onmouseup = null;
        }
    }
    
    function onMouseMove( e )
    {
        //console.log("mouse move: " + e.clientX);
        var delta = {x: e.clientX - md.e.x,
                     y: e.clientY - md.e.y};
        
        if (direction === "H" ) // Horizontal
        {
            // prevent negative-sized elements
            delta.x = Math.min(Math.max(delta.x, -md.firstWidth),
                               md.secondWidth);
            
            element.style.left = md.offsetLeft + delta.x + "px";
            first.style.width = (md.firstWidth + delta.x) + "px";
            second.style.width = (md.secondWidth - delta.x) + "px";
        }
    }
}


dragElement( document.getElementById("separator"), "H" );

</script></body></html>
3
personal_cloud

Hmm je suis tombé sur cette propriété en CSS3 . Cela pourrait être plus facile à utiliser . https://www.w3schools.com/cssref/css3_pr_resize.asp

2
ColacX

J'ai écrit un code simple pour cela sans aucune bibliothèque tierce; Ce code est seulement pour le séparateur horizontal (vertical est le même)

function onload()
{
	dragElement( document.getElementById("seperator"), "H" );
}

// function is used for dragging and moving
function dragElement( element, direction, handler )
{
  // Two variables for tracking positions of the cursor
  const drag = { x : 0, y : 0 };
  const delta = { x : 0, y : 0 };
  /* if present, the handler is where you move the DIV from
     otherwise, move the DIV from anywhere inside the DIV */
  handler ? ( handler.onmousedown = dragMouseDown ): ( element.onmousedown = dragMouseDown );

  // function that will be called whenever the down event of the mouse is raised
  function dragMouseDown( e )
  {
    drag.x = e.clientX;
    drag.y = e.clientY;
    document.onmousemove = onMouseMove;
    document.onmouseup = () => { document.onmousemove = document.onmouseup = null; }
  }

  // function that will be called whenever the up event of the mouse is raised
  function onMouseMove( e )
  {
    const currentX = e.clientX;
    const currentY = e.clientY;

    delta.x = currentX - drag.x;
    delta.y = currentY - drag.y;

    const offsetLeft = element.offsetLeft;
    const offsetTop = element.offsetTop;

	
	const first = document.getElementById("first");
	const second = document.getElementById("second");
	let firstWidth = first.offsetWidth;
	let secondWidth = second.offsetWidth;
  if (direction === "H" ) // Horizontal
	{
		element.style.left = offsetLeft + delta.x + "px";
		firstWidth += delta.x;
		secondWidth -= delta.x;
	}
    drag.x = currentX;
    drag.y = currentY;
	first.style.width = firstWidth + "px";
	second.style.width = secondWidth + "px";
  }
}
.splitter {
	width: 500px;
	height: 100px;
	display: flex;
}

#seperator {
	cursor: col-resize;
	background: url(https://raw.githubusercontent.com/RickStrahl/jquery-resizable/master/assets/vsizegrip.png) center center no-repeat #535353;	
	width: 10px;
	height: 100px;
	min-width: 10px;
}

#first {
	background-color: green;
	width: 100px;
	height: 100px;
	min-width: 10px;
}

#second {
	background-color: red;
	width: 390px;
	height: 100px;
	min-width: 10px;
}
<html>
<head>
<link rel="stylesheet" href="T10-Splitter.css">
<script src="T10-Splitter.js"></script>
</head>
<body onload="onload()">
<div class="splitter">
	<div id="first"></div>
	<div id="seperator"></div>
	<div id="second"></div>
</div>
</body>
</html>

2
Reza

Une approche totalement différente consiste à mettre des éléments dans une grille, telle que la grille ui ou la grille de Kendo, et à redimensionner les colonnes. Un inconvénient est que les utilisateurs ne pourraient pas redimensionner les lignes, bien que la taille des lignes puisse être définie par programme. 

2
Steve M

Vous pouvez utiliser le positionnement absolu ou absolu. Ce CSS, par exemple, ancrera une barre de 2em sur le côté gauche de votre page:

body {
    padding-left: 2.5em;
}
body > #bar {
    position:fixed;
    top:0; left:0;
    width: 2em;
    height: 100%;
    border-right: 2px solid #55F; background: #ddd;
}

( Démo sur jsfiddle.net )

2
Bergi

Avez-vous essayé la bibliothèque Dave Methwin, http://methvin.com/splitter/

2
Nate

Vous pouvez le faire avec JqueryUI sans une autre bibliothèque JS. Ajoutez simplement une fonction à l’événement .resizable resize pour ajuster la largeur de l’autre div.

$("#left_pane").resizable({
  handles: 'e',  // 'East' side of div draggable
  resize: function() {
  $("#right_pane").outerWidth( $("#container").innerWidth() - $("#left_pane").outerWidth() );
  }
});

Voici l'intégrale JS Fiddle .

2
freeworlder

J'ai trouvé splitter/ http://www.dreamchain.com/split-pane/ qui fonctionne avec jquery v1.9. Remarque Je devais ajouter le code CSS suivant pour le faire fonctionner avec la barre de navigation bootstrap corrigée.

fixed-left {
    position: absolute !important; /* to override relative */   
    height: auto !important;
    top: 55px; /* fixed navbar height */
    bottom: 0px;
}
1
TMa

Accordéon le plus simple, avec juste redimensionnement css . La règle débordement doit également être définie.

div {
  resize: vertical;
  overflow: auto;
  
  border: 1px solid
}

.menu {
  display: grid
  /* Try height: 100% or height: 100vh */
}
<div class="menu">

  <div>
    Hello world! 
  </div>
  <div>
    Hello world! 
  </div>
  <div>
    Hello world! 
  </div>
  <div>
    Hello world! 
  </div>
  <div>
    Hello world! 
  </div>
  <div>
    Hello world! 
  </div>
  
</div>

Vitres redimensionnables verticalement les plus simples:

div {
  resize: horizontal;
  overflow: auto;
  
  border: 1px solid;
  display: inline-flex;
  height:90vh
}
<div>
  Hello world! 
</div>
<div>
  Hello world! 
</div>
1
NVRM

Une bonne bibliothèque est Shield UI - vous pouvez jeter un oeil à leur flexible Splitter widget et au reste des composants puissants offerts par le framework.

0
Vladimir Georgiev