web-dev-qa-db-fra.com

Pourquoi les onglets Bootstrap affichent-ils des divisions de volet d'onglets avec des largeurs incorrectes lors de l'utilisation de graphiques?

Je crée donc une page avec un contenu à onglets en utilisant Bootstrap de Twitter, mais le contenu de ma div active de départ est toujours différent de celui de mes autres onglets. Par exemple, je mets des graphiques en utilisant highcharts.js dans mes différents onglets, mais celui actif s'affiche toujours correctement tandis que les autres ont une largeur incorrecte.

Découvrez l'exemple ci-dessous:

        <div class = "row-fluid">
        <div class = "span9">
            <div class = "row-fluid">
                <h3>Test</h3>

                    <ul class="nav nav-tabs">
                        <li class = "active">
                            <a data-toggle = "tab" href = "#one">One</a>
                        </li>
                        <li><a data-toggle = "tab" href = "#two">Two</a></li>
                        <li><a data-toggle = "tab" href = "#three">Three</a></li>
                    </ul>

                    <div class="tab-content">

                        <div class="tab-pane active" id="one" >
                            <h4>One</h4>
                            <div id = "container1"></div>
                            <script type = "text/javascript">
                                $(function () {
                                    $('#container1').highcharts({
                                        chart: {
                                        },
                                        xAxis: {
                                            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
                                        },
                                        series: [{
                                            data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]        
                                        }]
                                    });
                                });
                            </script>
                        </div>

                        <div class="tab-pane" id="two" >
                        <h4>Two</h4>
                        <div id = "container2"></div>
                        <script type = "text/javascript">
                            $(function () {
                                $('#container2').highcharts({
                                    chart: {
                                    },
                                    xAxis: {
                                        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
                                    },
                                    series: [{
                                        data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]        
                                    }]
                                });
                            });
                            </script>
                        </div>

                        <div class="tab-pane" id="three" >
                        <h4>Three</h4>
                        <div id = "container3"></div>
                        <script type = "text/javascript">
                            $(function () {
                                $('#container3').highcharts({
                                    chart: {
                                    },
                                    xAxis: {
                                        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
                                    },
                                    series: [{
                                        data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]        
                                    }]
                                });
                            });
                            </script>
                        </div>

                    </div> 
            </div>
        </div>
        <div class = "span3">
            <p>Here is the content on my sidebar</p>
        </div>
    </div>

Dans ce cas, le basculement de l'onglet actif au chargement de la page rend ce graphique correct pour moi, mais le reste s'étend toujours jusqu'au bord (dans le cas de mes données, que je veux seulement remplir l'espace de la plage9 div. Je viens d'utiliser des tableaux factices dans ce cas, mais c'est la même idée.

Voici un JSFiddle: http://jsfiddle.net/dw9tn/

Mes questions pour vous sont toutes:

1.) Est-ce juste moi?

2.) Que se passe-t-il exactement lorsque les onglets sont activés? En regardant le bootstrap css, cela semble traiter de display: none et display: block, mais je n'ai pas une bonne compréhension de la façon dont cela fonctionne dans ce cas.

3.) Est-ce un problème de highcharts ou un problème de bootstrap? J'ai remarqué que cela m'est arrivé avec des éléments non highchart (comme afficher des tweets dans la barre latérale), donc je me penche vers le bootstrap.

4.) Existe-t-il une solution pour que tout soit cohérent?

Merci les gars!

52
VirtualValentino

La cause

Ce n'est pas un problème de Highcharts, du moins pas en soi, le problème est dû au fait que Bootstrap utilise display: none pour masquer les onglets inactifs:

.tab-content > .tab-pane, .pill-content > .pill-pane {
    display: none;      /* this is the problem */
}

Cela provoque Highcharts pas en mesure d'obtenir la largeur attendue pour initialiser le graphique, donc par défaut à 600px. Cela arriverait à d'autres outils utilisant la même approche pour masquer le contenu.

Une solution CSS pure

Au lieu de contourner le problème avec un redessin supplémentaire ou une initialisation retardée, nous pouvons obtenir l'effet caché en utilisant height: 0; overflow-y: hidden, de cette façon, les volets d'onglets masqués sont toujours en place et ont un width valide:

/* bootstrap hack: fix content width inside hidden tabs */
.tab-content > .tab-pane:not(.active),
.pill-content > .pill-pane:not(.active) {
    display: block;
    height: 0;
    overflow-y: hidden;
} 
/* bootstrap hack end */

Mise à jour : la solution en 2 étapes précédente masque d'abord tous les onglets, puis rend à nouveau l'onglet actif visible. En comparaison, nous avons maintenant une solution en une étape, qui cible directement les onglets inactifs.

Cette solution est transparente, vous n'avez donc plus à vous soucier de savoir si le graphique est à l'intérieur d'un onglet ou non. Et il est efficace car il corrige le problème de largeur en premier lieu, il n'est donc pas nécessaire de contourner le problème de largeur par la suite via redimensionner/redessiner/refluer en utilisant javascript.

Remarque sur l'ordre en cascade

Ce correctif doit être chargé après bootstrap css, à cause de règles d'ordre de cascade CSS , en bref, la dernière règle gagne .

Démo

Avant vs Après

Astuce: passez à l'onglet Profil pour voir la différence.

148
ryenus

Le problème est que Highcharts ne peut pas calculer la largeur du conteneur qui a CSS: display:none, Donc la largeur par défaut (600px) est appliquée. En fait, le navigateur n'est pas en mesure de calculer la largeur de ces éléments.

Par exemple, lorsque vous utiliserez le séparateur pour redimensionner la fenêtre de résultats, le graphique se redimensionnera et fonctionnera. Vous avez donc trois options:

  • graphique de rendu après un premier clic sur cet onglet
  • rendre le graphique au début, mais après chaque clic et redimensionnement de la fenêtre, utilisez chart.setSize(w,h) avec une nouvelle largeur et hauteur
  • rendre le graphique au début, mais après l'onglet, cliquez sur appeler chart.reflow()
28
Paweł Fus

Sur la base de la réponse de Paweł, j'ai fait un exemple de travail:

http://codepen.io/colinsteinmann/pen/BlGfE

Fondamentalement, la fonction .reflow () est appelée sur chaque graphique lorsqu'un onglet est cliqué. De cette façon, le graphique est redessiné en fonction des nouvelles dimensions qui sont appliquées au conteneur lorsqu'il devient visible.

Il s'agit de l'extrait de code le plus important:

// fix dimensions of chart that was in a hidden element
jQuery(document).on( 'shown.bs.tab', 'a[data-toggle="tab"]', function (e) { // on tab selection event
    jQuery( ".contains-chart" ).each(function() { // target each element with the .contains-chart class
        var chart = jQuery(this).highcharts(); // target the chart itself
        chart.reflow() // reflow that chart
    });
})
5
metaColin

Sur la base de la réponse de Pawel, je rend le graphique au début, puis redimensionne le graphique.

Le code utilisé (avec bootstrap 3.0.3 et HighCharts 3.0.7)

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    $('#container').highcharts().setSize($('#container').width(),$('#container').height());
})

Source: http://getbootstrap.com/javascript/#tabs-usage

5
oaamados

J'ai trouvé une solution plus simple dans un autre article. Fondamentalement, le problème vient du fait que les Highcharts ne peuvent pas être rendus sur une div avec "display: none" défini. La solution consiste simplement à écrire un correctif dans votre feuille de style CSS.

.tab-content > .tab-pane,
.pill-content > .pill-pane {
    display: inline;
    visibility: hidden;
    position: absolute;
    width: 930px;
}

.tab-content > .active,
.pill-content > .active {
    display: inline;
    visibility: visible;
    position: absolute;
    width: 930px;
}

Cela va faire fonctionner les onglets avec l'attribut visibility au lieu de display. Les graphiques seront bien rendus.

1
Joel Luevano