barra de desplazamiento horizontal en la parte superior e inferior de la mesa

159

Tengo un muy grande tableen mi página. Así que decidí poner una barra de desplazamiento horizontal en la parte inferior de la mesa. Pero me gustaría que esta barra de desplazamiento también esté en la parte superior de la tabla.

Lo que tengo en la plantilla es esto:

<div style="overflow:auto; width:100%; height:130%">
<table id="data" style="width:100%">...</table>
</div>

¿Es posible hacerlo solo en HTML y CSS?

psoares
fuente
1
stackoverflow.com/questions/2274627/… Encontré esta solución útil.
VARSHA DAS

Respuestas:

234

Para simular una segunda barra de desplazamiento horizontal en la parte superior de un elemento, coloque un "maniquí" divencima del elemento que tiene desplazamiento horizontal, lo suficientemente alto como para una barra de desplazamiento. Luego, adjunte los controladores del evento "scroll" para el elemento ficticio y el elemento real, para sincronizar el otro elemento cuando se mueva cualquiera de las barras de desplazamiento. El elemento ficticio se verá como una segunda barra de desplazamiento horizontal sobre el elemento real.

Para ver un ejemplo en vivo , vea este violín

Aquí está el código :

HTML:

<div class="wrapper1">
  <div class="div1"></div>
</div>
<div class="wrapper2">
  <div class="div2">
    <!-- Content Here -->
  </div>
</div>

CSS:

.wrapper1, .wrapper2 {
  width: 300px;
  overflow-x: scroll;
  overflow-y:hidden;
}

.wrapper1 {height: 20px; }
.wrapper2 {height: 200px; }

.div1 {
  width:1000px;
  height: 20px;
}

.div2 {
  width:1000px;
  height: 200px;
  background-color: #88FF88;
  overflow: auto;
}

JS:

$(function(){
  $(".wrapper1").scroll(function(){
    $(".wrapper2").scrollLeft($(".wrapper1").scrollLeft());
  });
  $(".wrapper2").scroll(function(){
    $(".wrapper1").scrollLeft($(".wrapper2").scrollLeft());
  });
});
StanleyH
fuente
muy buena respuesta! ¡muchas gracias! :) así que traté de usar tu ejemplo, pero la barra de arriba no funciona, y cuando intenté aumentar el ancho, la barra de desplazamiento desaparece. alguna idea de por qué?
psoares
1
hiciste que funcionara? Para obtener más información sobre jQuery, consulte api.jquery.com/scrollLeft (Por supuesto, puede hacerlo sin jQuery adjuntando directamente los controladores de desplazamiento). Para una degradación elegante para los usuarios sin JS, puede agregar el div simulado al DOM por JS .
StanleyH
1
sí, lo hice funcionar, solo había agregado <script type = "text / javascript" src = "path"> </script> a <head>. Entonces, ¿cada vez que agrego jquery tenía que agregar el que agrega @fudgey? Lo siento, javascript y jquery todavía son algo chinos para mí
psoares
44
@StanleyH: ¿cómo configurar el div para que tome automáticamente el ancho de la tabla dentro de él? No quiero especificar el ancho de div2 manualmente, pero quiero que tome automáticamente el ancho de la tabla que contiene.
sqlchild
3
@CodyGuldner: ¿cómo configurar el div para que tome automáticamente el ancho de la tabla dentro de él? No quiero especificar el ancho de div2 manualmente, pero quiero que tome automáticamente el ancho de la tabla que contiene.
sqlchild
38

Intenta usar el jquery.doubleScrollcomplemento :

jQuery:

$(document).ready(function(){
  $('#double-scroll').doubleScroll();
});

CSS:

#double-scroll{
  width: 400px;
}

HTML:

<div id="double-scroll">
  <table id="very-wide-element">
    <tbody>
      <tr>
        <td></td>
      </tr>
    </tbody>
  </table>
</div>
pawel.suwala
fuente
55
Visite github.com/avianey/jqDoubleScroll para obtener una versión del increíble complemento de Pawel que no requiere jQueryUI.
fatal_error
1
El enlace conduce a un GitHub no mantenido con enlaces rotos en leerme. No he probado el js real.
Paul Gorbas
19

En primer lugar, una gran respuesta, @StanleyH. Si alguien se pregunta cómo hacer el contenedor de doble desplazamiento con ancho dinámico:

css

.wrapper1, .wrapper2 { width: 100%; overflow-x: scroll; overflow-y: hidden; }
.wrapper1 { height: 20px; }
.div1 { height: 20px; }
.div2 { overflow: none; }

js

$(function () {
    $('.wrapper1').on('scroll', function (e) {
        $('.wrapper2').scrollLeft($('.wrapper1').scrollLeft());
    }); 
    $('.wrapper2').on('scroll', function (e) {
        $('.wrapper1').scrollLeft($('.wrapper2').scrollLeft());
    });
});
$(window).on('load', function (e) {
    $('.div1').width($('table').width());
    $('.div2').width($('table').width());
});

html

<div class="wrapper1">
    <div class="div1"></div>
</div>
<div class="wrapper2">
    <div class="div2">
        <table>
            <tbody>
                <tr>
                    <td>table cell</td>
                    <td>table cell</td>
                    <!-- ... -->
                    <td>table cell</td>
                    <td>table cell</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

manifestación

http://jsfiddle.net/simo/67xSL/

simo
fuente
3
Utilícelo $('.div1').width( $('.div1')[0].scrollWidth)para obtener el ancho de desplazamiento real del contenido, útil cuando no está utilizando específicamente un contenedor como una tabla. @simo Increíble esfuerzo amigo.
Clain Dsilva
Para aclarar, también tuve que cambiar el código a scrollWidth para que mi propio código funcione donde el ancho del contenido dentro del div "div2" era variable debido al contenido dinámico del lado del servidor ubicado allí.
AdamJones
15

Sin JQuery (2017)

Como es posible que no necesite JQuery, aquí hay una versión funcional de Vanilla JS basada en la respuesta de @StanleyH:

var wrapper1 = document.getElementById('wrapper1');
var wrapper2 = document.getElementById('wrapper2');
wrapper1.onscroll = function() {
  wrapper2.scrollLeft = wrapper1.scrollLeft;
};
wrapper2.onscroll = function() {
  wrapper1.scrollLeft = wrapper2.scrollLeft;
};
#wrapper1, #wrapper2{width: 300px; border: none 0px RED;
overflow-x: scroll; overflow-y:hidden;}
#wrapper1{height: 20px; }
#wrapper2{height: 100px; }
#div1 {width:1000px; height: 20px; }
#div2 {width:1000px; height: 100px; background-color: #88FF88;
overflow: auto;}
<div id="wrapper1">
    <div id="div1">
    </div>
</div>
<div id="wrapper2">
    <div id="div2">
    aaaa bbbb cccc dddd aaaa bbbb cccc 
    dddd aaaa bbbb cccc dddd aaaa bbbb 
    cccc dddd aaaa bbbb cccc dddd aaaa 
    bbbb cccc dddd aaaa bbbb cccc dddd
    </div>
</div>

rap-2-h
fuente
esto en realidad no es receptivo / dinámico en el caso de que no conozca su ancho
elad silver
¡si! tiene las mismas advertencias que la respuesta original de @StanleyH
rap-2-h
11

Puede usar un complemento jQuery que hará el trabajo por usted:

El complemento manejará toda la lógica por ti.

avianey
fuente
2
Aunque este complemento hace lo mismo que suwala / jquery.doubleScroll, tiene más opciones como volver a calcular el ancho en window.resize
Ivan Hušnjak
1
Tampoco depende de jquery UI.
tribe84
1
Recomendaría este complemento, parece una versión mejorada de suwala / jquery.doubleScroll y funciona para mí
Russell England
Primero gracias por el gran complemento! Sin embargo, tengo un problema con la dirección de desplazamiento: rtl. Parece que no lo admite correctamente. Si alguno de ustedes, los gurús de JavaScripts, sabe cómo solucionarlo aquí es el violín: jsfiddle.net/qsn7tupc/3 Tenga en cuenta que funciona en Chrome pero en ningún otro navegador.
Vlado
10

La respuesta de StanleyH fue excelente, pero tuvo un error desafortunado: hacer clic en el área sombreada de la barra de desplazamiento ya no salta a la selección en la que hace clic. En cambio, lo que obtienes es un incremento muy pequeño y algo molesto en la posición de la barra de desplazamiento.

Probado: 4 versiones de Firefox (100% afectado), 4 versiones de Chrome (50% afectado).

Aquí está mi jsfiddle . Puede solucionar esto con una variable on / off (true / false) que permite que solo se active un evento onScroll () a la vez:

var scrolling = false;
$(".wrapper1").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
    scrolling = true;
    $(".wrapper2")
        .scrollLeft($(".wrapper1").scrollLeft());
});
$(".wrapper2").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
      scrolling = true;
    $(".wrapper1")
        .scrollLeft($(".wrapper2").scrollLeft());
});

Comportamiento problemático con respuesta aceptada:

Comportamiento realmente deseado:

Entonces, ¿por qué sucede esto? Si ejecuta el código, verá que wrapper1 llama a scrollLeft de wrapper2, y wrapper2 llama a scrollLeft de wrapper1, y repite esto infinitamente, por lo tanto, tenemos un problema de bucle infinito. O, más bien: el desplazamiento continuo del usuario entra en conflicto con la llamada de wrapperx al desplazamiento, se produce un conflicto de evento y el resultado final es no saltar en las barras de desplazamiento.

Espero que esto ayude a alguien más!

HoldOffHunger
fuente
gran explicación! de hecho estaba haciendo un bucle infinito
Ahmed Aboud
Si. ¡Muchas gracias por su apoyo! Es útil para mi.
Giang D.MAI
3

La vinculación de los desplazadores funcionó, pero en la forma en que está escrita, crea un bucle que hace que el desplazamiento sea lento en la mayoría de los navegadores si hace clic en la parte de la barra de desplazamiento más clara y la mantiene presionada (no al arrastrar el desplazador).

Lo arreglé con una bandera:

$(function() {
    x = 1;
    $(".wrapper1").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper2")
                .scrollLeft($(".wrapper1").scrollLeft());
        } else {
            x = 1;
        }
    });


    $(".wrapper2").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper1")
                .scrollLeft($(".wrapper2").scrollLeft());
        } else {
            x = 1;
        }
    });
});
Yossi Vainshtein
fuente
Esto resuelve un problema que tenía con las respuestas sugeridas aquí también. Sin embargo, esto solo mitiga el problema ligeramente, aún puede haber un desplazamiento gradual / lento si la distancia que desea desplazarse es lo suficientemente grande como para hacerlo.
Dan Temple
Con el condicional / flag, esta solución funciona bien y las pruebas coinciden con el comportamiento que esperaría sin aplicar JavaScript en el navegador.
userabuser
3

Una solución única de JavaScript que se basa en las respuestas @HoldOffHunger y @bobince

<div id="doublescroll">

.

function DoubleScroll(element) {
            var scrollbar= document.createElement('div');
            scrollbar.appendChild(document.createElement('div'));
            scrollbar.style.overflow= 'auto';
            scrollbar.style.overflowY= 'hidden';
            scrollbar.firstChild.style.width= element.scrollWidth+'px';
            scrollbar.firstChild.style.paddingTop= '1px';
            scrollbar.firstChild.appendChild(document.createTextNode('\xA0'));
            var running = false;
            scrollbar.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                element.scrollLeft= scrollbar.scrollLeft;
            };
            element.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                scrollbar.scrollLeft= element.scrollLeft;
            };
            element.parentNode.insertBefore(scrollbar, element);
        }

    DoubleScroll(document.getElementById('doublescroll'));
Ahmed Aboud
fuente
3

Basado en la solución @StanleyH, creé una directiva AngularJS , demostración en jsFiddle .

Fácil de usar:

<div data-double-scroll-bar-horizontal> {{content}} or static content </div>

Para desarrolladores de AngularJS

przno
fuente
31
"No se requiere jQuery". Sí, solo un marco completo. No es problema.
PitaJ
2

Hasta donde yo sé, esto no es posible con HTML y CSS.

punkrockbuddyholly
fuente
así que esto es realmente lo que pensaba .. Pero me gustaría conocer si alguien ha hecho esto y la mejor manera de hacer esto ..
psoares
Para HTML y CSS, no hay mejor manera. Es simplemente imposible. Necesita usar otras técnicas, como javascript, para obtener este tipo de funcionalidad.
Justus Romijn
1
¿Puedes dar algunos consejos para empezar a buscar?
psoares
2
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación.
SSA
2
@SSA responde la pregunta. La pregunta era "¿Es posible hacerlo solo en HTML y CSS?" y la respuesta a eso es "no".
punkrockbuddyholly
2

En vanilla Javascript / Angular puedes hacer esto así:

scroll() {
    let scroller = document.querySelector('.above-scroller');
    let table = document.querySelector('.table');
    table.scrollTo(scroller.scrollLeft,0);
  }

HTML:

<div class="above-scroller" (scroll)="scroll()">
  <div class="scroller"></div>
</div>
<div class="table" >
  <table></table>
</div>

CSS:

.above-scroller  {
   overflow-x: scroll;
   overflow-y:hidden;
   height: 20px;
   width: 1200px
 }

.scroller {
  width:4500px;
  height: 20px;
}

.table {
  width:100%;
  height: 100%;
  overflow: auto;
}
Jakub Bares
fuente
1

Ampliando la respuesta de StanleyH e intentando encontrar el mínimo requerido, esto es lo que implementé:

JavaScript (llamado una vez desde algún lugar como $(document).ready()):

function doubleScroll(){
        $(".topScrollVisible").scroll(function(){
            $(".tableWrapper")
                .scrollLeft($(".topScrollVisible").scrollLeft());
        });
        $(".tableWrapper").scroll(function(){
            $(".topScrollVisible")
                .scrollLeft($(".tableWrapper").scrollLeft());
        });
}

HTML (tenga en cuenta que los anchos cambiarán la longitud de la barra de desplazamiento):

<div class="topScrollVisible" style="overflow-x:scroll">
    <div class="topScrollTableLength" style="width:1520px; height:20px">
    </div>
</div>
<div class="tableWrapper" style="overflow:auto; height:100%;">
    <table id="myTable" style="width:1470px" class="myTableClass">
...
    </table>

Eso es.

MattC
fuente
1

a todos los fanáticos de angular / nativeJs, implementando la respuesta de @ simo

HTML (sin cambios)

<div class="top-scroll-wrapper">
    <div class="top-scroll"></div>
</div>

CSS (sin cambios, ancho: 90% es mi diseño)

.top-scroll-wrapper { width: 90%;height: 20px;margin: auto;padding: 0 16px;overflow-x: auto;overflow-y: hidden;}
.top-scroll { height: 20px; }

JS (como onload) o ngAfterViewChecked(todos asson para TypeScript)

let $topscroll = document.querySelector(".top-scroll") as HTMLElement
let $topscrollWrapper = document.querySelector(".top-scroll-wrapper") as HTMLElement
let $table = document.querySelectorAll('mat-card')[3] as HTMLElement

$topscroll.style.width = totalWidth + 'px'
$topscrollWrapper.onscroll = e => $table.scroll((e.target as HTMLElement).scrollLeft, 0)
$table.onscroll = e => $topscrollWrapper.scroll((e.target as HTMLElement).scrollLeft, 0)
bresleveloper
fuente
0

Si está utilizando iscroll.js en el navegador webkit o en el navegador móvil, puede intentar:

$('#pageWrapper>div:last-child').css('top', "0px");
diyism
fuente
0

Una directiva AngularJs para lograr esto: para usarlo, agregue la clase css double-hscroll a su elemento. Necesitarás jQuery y AngularJs para esto.

import angular from 'angular';

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $compile) {
  $scope.name = 'Dual wielded horizontal scroller';
});

app.directive('doubleHscroll', function($compile) {
  return {
restrict: 'C',
link: function(scope, elem, attr){

  var elemWidth = parseInt(elem[0].clientWidth);

  elem.wrap(`<div id='wrapscroll' style='width:${elemWidth}px;overflow:scroll'></div>`); 
  //note the top scroll contains an empty space as a 'trick' 
  $('#wrapscroll').before(`<div id='topscroll' style='height:20px; overflow:scroll;width:${elemWidth}px'><div style='min-width:${elemWidth}px'> </div></div>`);

  $(function(){
    $('#topscroll').scroll(function(){
      $("#wrapscroll").scrollLeft($("#topscroll").scrollLeft());
    });
    $('#wrapscroll').scroll(function() {
      $("#topscroll").scrollLeft($("#wrapscroll").scrollLeft());
    });

  });  

}

  };


});
Tore Aurstad
fuente
0

Aquí hay un ejemplo para VueJS

Página de inicio

<template>
  <div>
    <div ref="topScroll" class="top-scroll" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`,
          height: '12px'
        }"
      />
    </div>
    <div ref="content" class="content" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`
        }"
      >
        Lorem ipsum dolor sit amet, ipsum dictum vulputate molestie id magna,
        nunc laoreet maecenas, molestie ipsum donec lectus ut et sit, aut ut ut
        viverra vivamus mollis in, integer diam purus penatibus. Augue consequat
        quis phasellus non, congue tristique ac arcu cras ligula congue, elit
        hendrerit lectus faucibus arcu ligula a, id hendrerit dolor nec nec
        placerat. Vel ornare tincidunt tincidunt, erat amet mollis quisque, odio
        cursus gravida libero aliquam duis, dolor sed nulla dignissim praesent
        erat, voluptatem pede aliquam. Ut et tellus mi fermentum varius, feugiat
        nullam nunc ultrices, ullamcorper pede, nunc vestibulum, scelerisque
        nunc lectus integer. Nec id scelerisque vestibulum, elit sit, cursus
        neque varius. Fusce in, nunc donec, volutpat mauris wisi sem, non
        sapien. Pellentesque nisl, lectus eros hendrerit dui. In metus aptent
        consectetuer, sociosqu massa mus fermentum mauris dis, donec erat nunc
        orci.
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      contentWidth: 1000
    }
  },
  methods: {
    handleScroll(event) {
      if (event.target._prevClass === 'content') {
        this.$refs.topScroll.scrollLeft = this.$refs.content.scrollLeft
      } else {
        this.$refs.content.scrollLeft = this.$refs.topScroll.scrollLeft
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.top-scroll,
.content {
  overflow: auto;
  max-width: 100%;
}
.top-scroll {
  margin-top: 50px;
}
</style>

TOMA NOTA sobre el height: 12px... Lo hice 12px para que se notará en los usuarios de Mac también. Pero con Windows, 0.1px es lo suficientemente bueno

Dean Christian Armada
fuente
-1

Hay un problema con la dirección de desplazamiento: rtl. Parece que el complemento no lo admite correctamente. Aquí está el violín: violín

Tenga en cuenta que funciona correctamente en Chrome, pero en todos los demás navegadores populares la dirección de la barra de desplazamiento superior permanece a la izquierda.

Vlado
fuente