Developpez.com - Rubrique Dév. Web

Le Club des Développeurs et IT Pro

Créez une fenêtre modale avec CSS et jQuery

Un article de Soh Tanaka mis à jour par Didier Mouronval

Le 2009-10-20 21:53:32, par Bovino, Rédacteur
Bonjour,

Je vous propose une traduction de l'article anglophone de Soh Tanaka : CSS Lightview Style Popup.

Soh, tout au long de cet article, vous présente une méthode permettant de créer une popup CSS du même style que celles utilisées par la bibliothèque Lightview. Cette méthode utilise du CSS et un peu de JavaScript.

N'hésitez pas à nous faire part de vos questions/suggestions

Mise à jour du 10/02/2013 : la bibliothèque jQuery ayant beaucoup évolué depuis l'écriture de cet article, une mise à jour du code a été effectuée pour le rendre compatible avec les versions récentes de jQuery.

Créez une fenêtre modale avec CSS et jQuery.

Bonne lecture !
  Discussion forum
66 commentaires
  • le_chomeur
    Expert confirmé
    Il ne manque qu'une chose ( souvent oubliée ) => les listes déroulantes et objets flash passent au dessus ...

    il faut utiliser une iframe en background ...
  • McBenny
    Nouveau membre du Club
    Hello,

    Joli design mais un oubli de taille pour les puristes : l'accessibilité !
    Si je n'ai pas Javascript, je n'ai pas accès au contenu.

    Le principe de base il me semble est de donner accès au contenu, hors tout besoin technologique spécifique, puis d'améliorer l'expérience utilisateur.

    Dommage.
  • danielhagnoul
    Rédacteur
    Bonsoir

    L'article et le code sont intéressants, mais les codes (CSS, HTML, et jQuery) peuvent être améliorés.

    Ci-dessous ma version HTML5 (je travaille pour l'avenir ), elle fonctionne comme prévu dans IE9, Chrome 10 et Firefox 4.

    Pour les navigateurs obsolètes, le code du popup devrait fonctionner en remplaçant simplement le tag "section" par un tag "div".

    @le_chomeur : je ne vois pas le problème, avec le code CSS corrigé bien entendu.

    [Édition du 2011-06-20T22:00:00.000+02:00]

    Motif : correction du code de l'exemple.

    Lors du passage de la version 1.5.1 à la version 1.6+ la manière d'écrire un attribut data HTML5 a été modifiée. On doit maintenant impérativement écrire data-popup-class au lieu de data-popupClass, idem pour data-popup-width.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    <!doctype html>
    <html lang="fr">
    <head>
    	<meta http-equiv="X-UA-Compatible" content="chrome=1">
    	<meta charset="utf-8">
    	<meta name="Author" content="Daniel Hagnoul">
    	<title>Forum jQuery</title>
    	<style>
    		body { background-color:#dcdcdc; color:#000000; font-family:sans-serif; font-size:medium; font-style:normal; font-weight:normal; line-height:normal; letter-spacing:normal; }
    		h1,h2,h3,h4,h5 { font-family:serif; }
    		div,p,h1,h2,h3,h4,h5,h6,ul,ol,dl,form,table,img { margin:0px; padding:0px; }
            img {border:none; }
    		h1 { font-size:2em; text-shadow: 4px 4px 4px #bbbbbb; text-align:center; }
    		p { padding:6px; }
            ul,ol,dl {list-style:none; padding-left:6px; padding-top:6px; }
            li {padding-bottom:6px; }
    		.conteneur { width:95%; min-width:800px; min-height:500px; margin:12px auto; background-color:#FFFFFF; color:#000000; border:1px solid #666666; }
            		
    		/* TEST */
            .voile-noir {
                position: fixed;
                display: none;
                left: 0;
                top: 0; 
                width: 100%;
                height: 100%;
                opacity: 0.75;
                background: gray; 
                z-index: 9999;
            }
            .popup-block{
                position: fixed;
                display: none;
                top: 50%;
                left: 50%;
                padding: 20px; 	
                z-index: 99999;
                font-size: 1.2em;
                background: #fff;
                border: 20px solid #ddd;
                -webkit-box-shadow: 0px 0px 20px #000;
                -moz-box-shadow: 0px 0px 20px #000;
                box-shadow: 0px 0px 20px #000;
                -webkit-border-radius: 10px;
                -moz-border-radius: 10px;
                border-radius: 10px;
            }
            .popup p {
                padding: 5px 10px;
                margin: 5px 0;
            }
            .popup-btn-close {
                float: right; 
                margin: -55px -55px 0 0;
            }
        </style>
    </head>
    <body>
    	<h1>Forum jQuery</h1>
    	<section class="conteneur">
            <a href="#" class="popup-light" data-popup-class="popup-block" data-popup-width="500px">Voir la pop-up - Width = 500px</a>
            <!--
                Il ne manque qu'une chose ( souvent oublié ) => les listes déroulante et objet flash passent au dessus ...
                il faut utiliser une iframe en background ...
            -->
            <form style="display:block;width:300px;margin-left:500px;margin-top:100px;">
                <select>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option selected="selected">Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                    <option>Un mot pour remplir suffisament l'espace disponible</option>
                </select>
            </form>
    	</section>
        <section class="popup-block"> 
            <img src="http://sohtanaka.developpez.com/tutoriels/javascript/creez-fenetre-modale-avec-css-et-jquery/fichiers/bomber.gif" alt="Lil bomb dude" style="float: right; margin: 50px 0 0 20px;" /> 
            <h2>Popup #1</h2> 
            <p>Aliquip transverbero loquor esse ille vulputate exerci veniam fatua eros similis illum valde. Praesent, venio conventio rusticus antehabeo lenis. Melior pertineo feugait, praesent hos rusticus et haero facilisis abluo. </p> 
            <p>Veniam tincidunt augue abluo vero, augue nisl melior quidem secundum nobis singularis eum eum.</p>
        </section>
    	<script charset="utf-8" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
        <script>
            $(function(){
                $(".popup-light").click(function() {
                    var obj = $(this),
                        popupClass = obj.data("popupClass"),
                        popupWidth = obj.data("popupWidth"),
                        objPopup =  $('.' + popupClass);
                    
                    objPopup
                        .css("width", popupWidth)
                        .prepend('<img src="http://sohtanaka.developpez.com/tutoriels/javascript/creez-fenetre-modale-avec-css-et-jquery/fichiers/close_pop.png" class="popup-btn-close" title="Close Window" alt="Close" />')
                        .css({
                            // Si l'on regroupe les deux blocs CSS, le popup n'est pas bien positionné
                            // Le popup doit avoir sa taille définitive avant le calcul de outerHeight et de outerWidth
                            "margin-top":  -objPopup.outerHeight(true)/2,
                            "margin-left": -objPopup.outerWidth(true)/2
                        })
                        .fadeIn();
                    
                    $("<div/>", {
                        "class":"voile-noir",
                        "css":{
                            "filter":"alpha(opacity=80)"
                        }
                    }).appendTo("body").fadeIn();
                    
                    return false;
                });
                
                $("body").delegate(".popup-btn-close, .voile-noir", "click", function(){
                    $('.voile-noir , .popup-block').fadeOut(function(){
                        $(".popup-btn-close, .voile-noir").remove();
                    });
                    
                    return false;
                });
            });
        </script>
    </body>  
    </html>
  • Bovino
    Rédacteur
    Non, il est strictement interdit de mettre un formulaire d'inscription dans cette fenêtre !

    Plus sérieusement, le contenu de la fenêtre est du code HTML classique, qu'est-ce qui t'empêcherait d'y mettre un formulaire ?
  • SpaceFrog
    Rédacteur/Modérateur
    Je rencontre beaucoup de soucis de compatibilité sous IE

    IE6 => attention a la transparence des png !
    le bouton close en particulier ... on peut mettre un gif à la place.
    ou tenter d'utiliser un pngfix.
    IE7 => marche pas du tout
    IE8 => le bouton de fermeture est derrière le cadre
    réoslu en modifiant le css ainsi
    Code :
    1
    2
    3
    4
    5
    6
    7
    img.btn_close {
    	position:relative;
    	z-index:5;
    	border:0;
    	float: right;
    	margin: -55px -55px 0 0;
    }
    ...
  • Acasapeubas
    Futur Membre du Club
    Bonjour,

    ==> Asli Bilal

    Pour ton problème de fermeture de fenêtre modale. Tu dois ajouter dans le HTML :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div id="popup_name" class="popup_block">
    	<h2>Developpez.com</h2>
    	<p>Soh Tanaka est traduit sur developpez.com. 
                  <a class="close" href="#" title="Fermeture" ></a>
           </p>
    
    
    </div>
    Car dans le script il y a :
    Code :
    1
    2
    3
    4
    5
    6
    7
    //Fermeture de la pop-up et du fond
    $('a.close, #fade').live('click', function() { //Au clic sur le bouton ou sur le calque...
    	$('#fade , .popup_block').fadeOut(function() {
    		$('#fade, a.close').remove();  //...ils disparaissent ensemble
    	});
    	return false;
    });
    Si tu le souhaites, tu peux aussi le faire avec une image.

    En espérant t'avoir aidé.

    ==>Allez plus loin.<==

    Une fois la fenêtre modale fermé, si je reclique sur le lien d'ouverture de celle-ci. Le lien ou l'image de fermeture a disparu sauf si je réactualise !
    Pour éviter cela, j'ai enlevé :
    Code :
    .remove()
    Dans :
    Code :
    1
    2
    3
    4
    5
    6
    7
    //Fermeture de la pop-up et du fond
    $('a.close, #fade').live('click', function() { //Au clic sur le bouton ou sur le calque...
    	$('#fade , .popup_block').fadeOut(function() {
    		$('#fade, a.close').remove();  //...ils disparaissent ensemble
    	});
    	return false;
    });
    Soit [Désolé pour la coloration rouge:oops: pourtant il n'ya pas de balise COLOR dans le code ci-dessous !]:
    Code :
    1
    2
    3
    4
    5
    6
    7
    //Fermeture de la pop-up et du fond
    $('a.close, #fade').live('click', function() { //Au clic sur le bouton ou sur le calque...
    	$('#fade , .popup_block').fadeOut(function() {
    		$('#fade, a.close');  //...ils disparaissent ensemble
    	});
    	return false;
    });
    Cela est fonctionnel. Néanmoins, est-ce que cette méthode fait parti des bonnes pratiques de programmation ? Ou il y a une autre façon plus propre, plus pro d'arriver à ce résultat ?

    Merci de m'éclairer.

    Bon week-end à tous.
  • Bovino
    Rédacteur
    Effectivement, le code jQuery de l'article n'est pas compatible avec les versions récentes de jQuery.
    D'autre part, les code HTML était sémantiquement faux.

    Une mise à jour de l'article a donc été faite passant l'exemple en HTML5 et rendant le code jQuery compatible avec les dernières versions.
  • Bovino
    Rédacteur
    Oui, c'est bien un problème de scope.
    Tes deux codes se trouvent dans deux closures différentes, du coup, les fonctions de l'une sont inaccessibles depuis l'autre.
    Regroupe ton code dans une seule closure et ça devrait mieux fonctionner.

    D'autre part, un petit détail par rapport à la notation
    Code :
    (function(){...})();
    là aussi, si tu utilises jQuery dedans, il est recommandé pour éviter tout conflit de transmettre l'objet jQuery :
    Code :
    (function($){...})(jQuery);
  • jojolito
    Futur Membre du Club
    Bonsoir,
    Dans le précédent message le chômeur fait une remarque sur cette méthode et écrit : "il faut utiliser une iframe en background ..."
    En effet, lorsque la popup est ouverte au-dessus de la zone opacifiée le fait de passer la souris sur cette zone déclenche le déploiement de la liste déroulante.
    Vous serait-il possible de me donner plus d'informations pour éviter cela ?
    Merci pour votre réponse
    Jojolito
  • le_chomeur
    Expert confirmé
    Salut danielhagnoul

    Sous ie6/7 firefox 3.X , les éléments flash ainsi que les listes déroulantes passaient par dessus quelque soit le z-index

    je viens de tester , très bel exemple , fonctionne parfaitement sous firefox 4.0 , chrome , mais plante sous ie8 :


    Message*: Demande d'accès à la méthode ou aux propriétés inattendue.
    Ligne*: 16
    Caractère*: 55923
    Code*: 0
    URI*: http://code.jquery.com/jquery-1.5.1.min.js
    pour la compatibilité je génèrerais tout de même une iframe en visibilité hidden

    EDIT : la phrase navigateur obsolète m'avait échappé méa culpa ^^