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 |
$(document).ready(function(){ // On récupère la largeur de chaque image. // Si l'image a une largeur inférieure ou égale à 1224px // on ajoute une classe ".container" à l'élément ".cRow". function setClassForImageContainer(htmlElement){ $(htmlElement).each(function(){ var img = $(this)[0]; $('<img/>') .attr('src', $(img).attr('src')) .on('load', function(){ if(this.width <= 1224){ $(img).closest('.cRow').addClass('container'); } }); }); } function setClassForOtherContainer(){ $('div.cRow').each(function(){ // Tous les blocs ".cRow" qui ne font pas l'objet d'un // traitement spécifique via une autre fonction. // Si l'élément ".cRow" contient une image // c'est la fonction "setClassForImageContainer" // qui s'occupe d'attribuer ou non la classe ".container". if($(this).find('div.image-container').length != 0){ // do nuffin' } // Sinon : else{ $(this).addClass('container'); } }); } // si gabarit 2 colonnes if($('body#tplSidebar').length != 0){ // console.log('gabarit 2 colonnes'); $('section#heading').addClass('container-xl'); // Pour les blocs ".cRow" qui contiennent des images, mais uniquement dans "#heading" : setClassForImageContainer('#heading div.image-container img'); } // si gabarit 1 colonne else if($('body#tplNosidebar').length != 0){ // console.log('gabarit 1 colonne'); $('section#content').addClass('container-xl'); // Pour tous blocs ".cRow" de la page qui contiennent des images : setClassForImageContainer('div.image-container img'); // Pour les blocs ".cRow" qui ne font pas l'objet d'un traitement spécifique via une autre fonction : setClassForOtherContainer(); } }); |
Mois : septembre 2016
[CSS] Changer la couleur et l’apparence des puces de l’élément UL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
ul.normal{ list-style-type: none; li{ &:before{ display: inline-block; vertical-align: middle; margin-top: -4px; margin-left: -(($grid-gutter-width/3) + 4); content: ""; width: 8px; height: 8px; background-color: $corporate-color-one; border-radius: 50%; margin-right: $grid-gutter-width/3; } } } |
[jQuery] Vérifier, au clic, la présence d’une classe dans le DOM et afficher ou masquer des éléments en fonction
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 |
// Par défaut, on masque les éléments qui ne doivent être visibles que lorsque la classe "is-active" est présente dans le DOM $('#showIfLinkIsActive').addClass('hidden'); // Fonction qui vérifie si la classe "is-active" est présente dans le DOM function setElementVisibility(){ if($('.foo-element a.link').hasClass('is-active')){ $('#showIfLinkIsActive').removeClass('hidden'); } else{ $('#showIfLinkIsActive').addClass('hidden'); } } // Au clic sur un lien, on lance la fonction ci-dessus (on attend 100ms que la classe ".is-active" fasse son apparition dans le DOM) $('.foo-element a.link').on('click', function(){ setTimeout(setElementVisibility, 100); }); // Au clic n'importe où dans le document (fermeture automatique du lien ouvert), on relance la fonction ci-dessus... $(document).on('click', function(){ setTimeout(setElementVisibility, 100); }); // ...mais le lien ouvert ne doit pas se fermer au clic sur ces éléments var fooElements = $('.foo-element, .foo-element2, .foo-element3'); fooElements.on('click', function(e){ e.stopPropagation(); }); |
Optimiser et synchroniser l’exécution de media queries CSS et JS avec Sync MQ
Alternative intéressante: @include-media – Simple, elegant and maintainable media queries in Sass. Couplé à include-media-export – An include-media plugin for exporting breakpoints from Sass to JavaScript.
Avant propos : certains des CMS les plus récents du marché proposent nativement des solutions équivalentes à Sync MQ pour gérer et/ou synchroniser l’exécution de media queries CSS et JS. Pour d’évidentes raisons de compréhension et de maintenabilité de votre code source, je vous conseille de vous tourner plutôt vers ces solutions lorsqu’elles existent.
Sync MQ: pour quoi faire?
Qu’on démarre un projet de site internet de zéro ou qu’un client nous demande une nouvelle mouture, à destination des supports mobiles, de son site existant (qui tourne sous une solution qui ne prend pas en charge les concepts de responsive design), la question de la gestion et de l’adaptation de l’affichage sur différents périphériques de navigation (ordinateurs, tablettes, smartphones) se pose rapidement. Si l’utilisation de media queries s’impose immédiatement comme une évidence dans nos feuilles de styles qu’en est-il en revanche de l’exécution, pour un support donné, de code JavaScript? Et existe-t’il un moyen simple de gérer, d’optimiser votre code CSS (ou LESS, ou SASS, ou autre préprocesseur…) et JS et de synchroniser leur exécution ?
C’est pour répondre à cette double problématique qu’intervient Sync MQ dont le concept est :
- de simplifier l’écriture et la déclaration de media queries par rapport aux méthodes traditionnelles,
- de faciliter la synchronisation de l’exécution de media queries tant au niveau de vos styles que du code JavaScript.
Les sources de Sync MQ que vous trouverez sous GitHub à l’heure ou j’écris ces lignes exploitent des dépendances telles qu’Enquire JS et le composant Grid de Bootstrap 3 parce que c’est celles avec lesquelles j’aime travailler. Mais Sync MQ est avant tout un concept que rien ne vous empêche d’intégrer à vos propres habitudes de travail. Vous pouvez tout-à-fait remplacer Enquire JS par la brique mq de Modernizr ou le composant Grid de Bootstrap 3 par celui proposé par le framework Foundation 4.
De l’art de bien choisir ses points de rupture.
=> Web Stats
Et mon code JavaScript dans tout ça?
Quel intérêt de faire appel à une dépendance telle qu’Enquire JS alors qu’une ligne de code JavaScript suffirait à exécuter du code pour un support donné?
Pour un point de rupture donné (mettons, 800px) et suivant le navigateur utilisé, la méthode $(window).width()
de jQuery et les Media Queries CSS3 ne sont pas exécutées systématiquement au même moment.
1 2 3 4 5 |
$(window).resize(function(){ if ($(window).width() <= 800){ // faire quelque chose ici... } }); |
A Code Example of the Difference Between jQuery Window Width and CSS Media Query width measurements.
Dans cet exemple, l’auteur démontre que […].
On commence par créer des variables aux libellés parlants pour remplacer le code (moins digeste) traditionnellement utilisé en CSS pour la déclaration de media queries.
1 2 3 4 5 6 7 |
$bpMobile: "(max-width: #{$screen-sm-max})"; $bpSmartphone: "(max-width: #{$screen-xs-max})"; $bpTablet: "(min-width: #{$screen-sm-min}) and (max-width: #{$screen-sm-max})"; $bpTabletUp: "(min-width: #{$screen-sm-min})"; $bpDesktop: "(min-width: #{$screen-md-min})"; $bpSmallDesktop: "(min-width: #{$screen-md-min}) and (max-width: #{$screen-md-max})"; $bpLargeDesktop: "(min-width: #{$screen-lg-min})"; |
Comme décrit plus haut, les points de rupture retenus ne ciblent pas uniquement un ou plusieurs supports donnés (iPhone, iPad, Amstrad CPC) en fonction de leurs résolutions mais :
- des ensembles moyens de résolutions rencontrées par périphériques (Smartphone, Tablette, Desktop),
- les résolutions que les clients nous demandent le plus souvent de cibler.
Les valeurs affectées à ces variables aux libellés allégés font directement référence à celles des points de rupture définis dans les variables du framework Bootstrap 3 (version SASS).
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 |
//== Media queries breakpoints // //## Define the breakpoints at which your layout will change, adapting to different screen sizes. // Extra small screen / phone //** Deprecated `$screen-xs` as of v3.0.1 $screen-xs: 480px !default; //** Deprecated `$screen-xs-min` as of v3.2.0 $screen-xs-min: $screen-xs !default; //** Deprecated `$screen-phone` as of v3.0.1 $screen-phone: $screen-xs-min !default; // Small screen / tablet //** Deprecated `$screen-sm` as of v3.0.1 $screen-sm: 768px !default; $screen-sm-min: $screen-sm !default; //** Deprecated `$screen-tablet` as of v3.0.1 $screen-tablet: $screen-sm-min !default; // Medium screen / desktop //** Deprecated `$screen-md` as of v3.0.1 $screen-md: 992px !default; $screen-md-min: $screen-md !default; //** Deprecated `$screen-desktop` as of v3.0.1 $screen-desktop: $screen-md-min !default; // Large screen / wide desktop //** Deprecated `$screen-lg` as of v3.0.1 $screen-lg: 1200px !default; $screen-lg-min: $screen-lg !default; //** Deprecated `$screen-lg-desktop` as of v3.0.1 $screen-lg-desktop: $screen-lg-min !default; // So media queries don't overlap when required, provide a maximum $screen-xs-max: ($screen-sm-min - 1) !default; $screen-sm-max: ($screen-md-min - 1) !default; $screen-md-max: ($screen-lg-min - 1) !default; |
Ces mêmes valeurs sont immédiatement ré-exploitées dans Bootstrap pour construire les styles du composant Grid.
Aussi, on retrouvera dans Sync MQ parmi les habituelles Smartphone, Tablette et Desktop, des media queries englobant:
- l’ensemble des Mobiles (
$bpMobile
pour Smartphone et Tablette), - les Tablettes et au-delà (
$bpTabletUp
), - les petits et larges Desktops séparément (
$bpSmallDesktop
et$bpLargeDesktop
).
Pour cibler par exemple les résolutions à partir des tablettes et au-delà, au lieu d’écrire:
1 |
@media (min-width: #{$screen-sm-min}) { body{ border: 10px solid tomato; } } |
J’écris désormais:
1 |
@media #{$bpTabletUp} { body{ border: 10px solid tomato; } } |
Quelques astuces d’utilisation:
- Lorsque vous choisissez un plug-in JS amené à être exécuté en fonction d’un point de rupture, veillez à ce qu’il possède une méthode
.destroy()
et/ou.reload()
. C’est le cas, par exemple, du carousel BxSlider. La présence de ce type d’options vous dispensera de nettoyer vous-même un DOM modifié par l’exécution d’un plug-in lorsque vous souhaiterez en annuler les effets pour une vue donnée. - Trois résolutions sont en réalité disponibles pour Amstrad CPC: 160×200 pixels avec 16 couleurs, 320×200 pixels avec 4 couleurs, et 640×200 pixels avec 2 couleurs. De quoi rentabiliser immédiatement l’utilisation de Sync MQ.
Un peu de documentation:
- enquire JS
- Bootsrap 3 Grid component mediaqueries
- Bootstrap SASS variables
- Defining Breakpoints sur Open Web
- Where And How To Set Breakpoints In Media Queries
- Firing Responsive jQuery Functions based on CSS Media Queries Rather than Window Width – jQuery
$(window).width()
and CSS3 Media Queries do not always match. - Abnormal media query handling in Fire Fox
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<p><a href="http://getbootstrap.com/css/#grid">Bootstrap 3 grid component documentation</a></p> <h2>CSS mediaqueries :</h2> <div class="css-mediaqueries"> <p class="bp bpMobile">bpMobile</p> <p class="bp bpSmartphone">bpSmartphone</p> <p class="bp bpTablet">bpTablet</p> <p class="bp bpTabletUp">bpTabletUp (Tablet + up)</p> <p class="bp bpDesktop">bpDesktop</p> <p class="bp bpSmallDesktop">bpSmallDesktop</p> <p class="bp bpLargeDesktop">bpLargeDesktop</p> </div> <h2>JS mediaqueries :</h2> <div class="js-mediaqueries"> <p class="bp js-bpMobile">bpMobile</p> <p class="bp js-bpSmartphone">bpSmartphone</p> <p class="bp js-bpTablet">bpTablet</p> <p class="bp js-bpTabletUp">bpTabletUp (Tablet + up)</p> <p class="bp js-bpDesktop">bpDesktop</p> <p class="bp js-bpSmallDesktop">bpSmallDesktop</p> <p class="bp js-bpLargeDesktop">bpLargeDesktop</p> </div> |
CSS (SASS)
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 |
// from: https://github.com/twbs/bootstrap-sass/blob/3.3-stable/assets/stylesheets/bootstrap/_variables.scss#L286 //== Media queries breakpoints // //## Define the breakpoints at which your layout will change, adapting to different screen sizes. // Extra small screen / phone //** Deprecated `$screen-xs` as of v3.0.1 $screen-xs: 480px !default; //** Deprecated `$screen-xs-min` as of v3.2.0 $screen-xs-min: $screen-xs !default; //** Deprecated `$screen-phone` as of v3.0.1 $screen-phone: $screen-xs-min !default; // Small screen / tablet //** Deprecated `$screen-sm` as of v3.0.1 $screen-sm: 768px !default; $screen-sm-min: $screen-sm !default; //** Deprecated `$screen-tablet` as of v3.0.1 $screen-tablet: $screen-sm-min !default; // Medium screen / desktop //** Deprecated `$screen-md` as of v3.0.1 $screen-md: 992px !default; $screen-md-min: $screen-md !default; //** Deprecated `$screen-desktop` as of v3.0.1 $screen-desktop: $screen-md-min !default; // Large screen / wide desktop //** Deprecated `$screen-lg` as of v3.0.1 $screen-lg: 1200px !default; $screen-lg-min: $screen-lg !default; //** Deprecated `$screen-lg-desktop` as of v3.0.1 $screen-lg-desktop: $screen-lg-min !default; // So media queries don't overlap when required, provide a maximum $screen-xs-max: ($screen-sm-min - 1) !default; $screen-sm-max: ($screen-md-min - 1) !default; $screen-md-max: ($screen-lg-min - 1) !default; // Breakpoints aliases $bpSmartphone: "(max-width: #{$screen-xs-max})"; $bpTablet: "(min-width: #{$screen-sm-min}) and (max-width: #{$screen-sm-max})"; $bpSmallDesktop: "(min-width: #{$screen-md-min}) and (max-width: #{$screen-md-max})"; $bpLargeDesktop: "(min-width: #{$screen-lg-min})"; $bpMobile: "(max-width: #{$screen-sm-max})"; $bpTabletUp: "(min-width: #{$screen-sm-min})"; $bpDesktop: "(min-width: #{$screen-md-min})"; // See it in action : .css-mediaqueries .bp{ display: none; } @media #{$bpMobile} { .bp.bpMobile{ display: block; } } @media #{$bpSmartphone} { .bp.bpSmartphone{ display: block; } } @media #{$bpTablet} { .bp.bpTablet{ display: block; } } @media #{$bpTabletUp} { .bp.bpTabletUp{ display: block; } } @media #{$bpDesktop} { .bp.bpDesktop{ display: block; } } @media #{$bpSmallDesktop} { .bp.bpSmallDesktop{ display: block; } } @media #{$bpLargeDesktop} { .bp.bpLargeDesktop{ display: block; } } |
JS (enquire, jQuery)
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 |
// enquire JS documentation : http://wicky.nillia.ms/enquire.js/ // breakpoints global vars // bootstrap grid breakpoints values // from: https://github.com/twbs/bootstrap-sass/blob/3.3-stable/assets/stylesheets/bootstrap/_variables.scss#L286 var bs_screen_xs_min = '480'; bs_screen_sm_min = '768'; bs_screen_md_min = '992'; bs_screen_lg_min = '1200'; bs_screen_xs_max = bs_screen_sm_min - 1; bs_screen_sm_max = bs_screen_md_min - 1; bs_screen_md_max = bs_screen_lg_min - 1; // enquire JS breakpoints aliases // (as seen on Bootstrap documentation: http://getbootstrap.com/css/#grid-media-queries) bpSmartphone = 'screen and (max-width: '+ bs_screen_xs_max +'px)'; bpTablet = 'screen and (min-width: '+ bs_screen_sm_min +'px) and (max-width: '+ bs_screen_sm_max +'px)'; bpSmallDesktop = 'screen and (min-width: '+ bs_screen_md_min +'px) and (max-width: '+ bs_screen_md_max +'px)'; bpLargeDesktop = 'screen and (min-width: '+ bs_screen_lg_min +'px)'; bpMobile = 'screen and (max-width: '+ bs_screen_sm_max +'px)'; bpTabletUp = 'screen and (min-width: '+ bs_screen_sm_min +'px)'; bpDesktop = 'screen and (min-width: '+ bs_screen_md_min +'px)'; function resetJSDOM(){ $('.js-mediaqueries p.bp').hide(); } resetJSDOM(); // enquire JS enquire.register(bpMobile, { match : function() { // console.log('bpMobile'); $('p.bp.js-bpMobile').show(); }, unmatch : function() { $('p.bp.js-bpMobile').hide(); } }); enquire.register(bpSmartphone, { match : function() { // console.log('bpSmartphone'); $('p.bp.js-bpSmartphone').show(); }, unmatch : function() { $('p.bp.js-bpSmartphone').hide(); } }); enquire.register(bpTablet, { match : function() { // console.log('bpTablet'); $('p.bp.js-bpTablet').show(); }, unmatch : function() { $('p.bp.js-bpTablet').hide(); } }); enquire.register(bpTabletUp, { match : function() { // console.log('bpTabletUp'); $('p.bp.js-bpTabletUp').show(); }, unmatch : function() { $('p.bp.js-bpTabletUp').hide(); } }); enquire.register(bpDesktop, { match : function() { // console.log('bpDesktop'); $('p.bp.js-bpDesktop').show(); }, unmatch : function() { $('p.bp.js-bpDesktop').hide(); } }); enquire.register(bpSmallDesktop, { match : function() { // console.log('bpSmallDesktop'); $('p.bp.js-bpSmallDesktop').show(); }, unmatch : function() { $('p.bp.js-bpSmallDesktop').hide(); } }); enquire.register(bpLargeDesktop, { match : function() { // console.log('bpLargeDesktop'); $('p.bp.js-bpLargeDesktop').show(); }, unmatch : function() { $('p.bp.js-bpLargeDesktop').hide(); } }); |
[Gulp] Génération d’une police d’icônes avec template en SASS
- Tutoriel : ICONFONT : GÉNÉRATION VIA GULP.JS
- Plug-in Gulp sur github.com : gulp-icon-font – Générer une police d’icône (iconfont) à partir de fichiers SVG.
- Sur npmjs.com – gulp-iconfont – Create icon fonts from several SVG icons.
- How to generate an iconfont styleguide with Gulp
Attention : préférer les sources hébergées sur github.com à celles présentes dans les codebits du tutoriel.
template sass
Par rapport au tutoriel et aux sources du plug-in sur github.com, notez la présence d’un mixin init-icon-font.
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 |
@mixin init-icon-font(){ display: inline-block; font-family: '<%= fontName %>'; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; font-style: normal; font-variant: normal; font-weight: normal; line-height: 1; text-transform: none; } @font-face { font-family: '<%= fontName %>'; font-weight: normal; font-style: normal; src: url('<%= fontPath %><%= fontName %>.eot'); src: url('<%= fontPath %><%= fontName %>.woff2') format('woff2'), url('<%= fontPath %><%= fontName %>.woff') format('woff'), url('<%= fontPath %><%= fontName %>.ttf') format('truetype'), url('<%= fontPath %><%= fontName %>.eot?#iefix') format('embedded-opentype'); } .<%= className %>[class^="<%= className %>-"], .<%= className %>[class*=" <%= className %>-"], [class*="-<%= className %>-"]{ @include init-icon-font(); } $icons: ( <%= glyphs.map(function(glyph) { return glyph.name + ': \'' + '\\' + glyph.unicode[0].charCodeAt(0) .toString(16).toUpperCase() + '\'' }).join(',\n ') %> ); @each $name, $icon in $icons { .<%= className %>-#{$name} { &:before { content: $icon; } } } |
gulpfile.js
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 |
var gulp = require('gulp'); sass = require('gulp-sass'); iconfont = require('gulp-iconfont'); gulp.task('iconfont', function () { gulp.src('src/icons/**/*.svg') .pipe(iconfont({ fontName: 'project' , prependUnicode: true , formats: ['ttf', 'eot', 'woff', 'woff2'] , timestamp: runTimestamp , normalize: true , fontHeight: 1001 , centerHorizontally: true })) .on('glyphs', function (glyphs) { console.log(glyphs); gulp.src('src/sass/templates/_icons.scss') .pipe(consolidate('lodash', { glyphs: glyphs , fontName: 'project' , fontPath: '/media/themes/project/icons/' , className: 'icon' })).on('error', function(e){console.log(e);}) .pipe(gulp.dest('src/sass')); }) .pipe(gulp.dest('image/icons')); }); gulp.task('sass', function(){ return gulp.src('src/sass/**/*.scss') .pipe(sass().on('error', sass.logError)) .pipe(gulp.dest('style')) }); // Watch every tasks with 'gulp watch' gulp.task('watch', ['iconfont', 'sass'], function(){}); |
Utilisation dans des sources SASS :
1 2 3 4 5 6 7 8 9 10 11 |
.element{ &:after{ @include init-icon-font(); content: '\EA13'; } &.is-active{ &:after{ transform : translateY(-50%) rotate(180deg); } } } |
(bonus) Markup HTML planche d’icônes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<ul class="doc-iconlist"> <li><i class="icon icon-"></i><p>icon icon-</p></li> </ul> <style type="text/css"> .doc-iconlist li{ width: 12.50%; height: 115px; padding: 10px; float: left; text-align: center; border: 1px solid #fff; background-color: #eee; } .doc-iconlist i{ font-size: 2.6em; } </style> |
How to generate an iconfont styleguide with Gulp
Source: How to generate html page with elements from scss in Gulp
sur Stack Overflow
Here is an example using the jade templating engine. This will read the file ./test.scss, extract all the icon-* words and generate a ./template.html file:
Gulpfile.js:
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 |
// npm i gulp gulp-jade --save-dev var gulp = require('gulp'), jade = require('gulp-jade'), fs = require('fs'); gulp.task('default', function () { var re = new RegExp(/icon-(\w+)/); fs.readFile('./test.scss', 'utf8', function(err, data) { var icons = [] if(err) return console.log(err); data.split('\r\n').forEach(function(icon) { var match = re.exec(icon); if(match) icons.push('icon-' + match[1]) }) // the gulp-jade plugin expects template local data to be an object // such as: // {locals: YOUR_DATA_OBJECT_TO_BIND} bind({locals: {icons: icons}}) }); // method that will bind data to your template var bind = function(data) { gulp.src('./template.jade') .pipe(jade(data)) .pipe(gulp.dest('./')) } }); |
./test.scss:
1 2 3 4 5 6 7 8 9 10 11 12 |
.icon-calendar { @include icon(calendar); } .icon-circle { @include icon(circle); } .icon-sun { @include icon(sun); } .icon-home { @include icon(home); } |
./template.jade
The icons variable comes from the {locals: {icons: {}} argument in the .pipe(jade(data)) call.
1 2 3 4 5 6 7 8 9 |
doctype html html(lang="en") head // you may want to add a link to your compiled `css` file for a nicer display body for ic in icons i(class=ic) |. = ic |
[jQuery] Compter le nombre d’enfants dans chaque parent et ajouter une classe spécifique en fonction du résultat
Source : jQuery count number of li’s in each ul.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$.each($('.meganav-level2 .container .row'), function() { var children = $(this).find('> .meganav-level2-item'); var count = children.length; $(this).attr('data-columns', count); if(count == 2){ children.addClass('col-md-6'); } else if(count == 3){ children.addClass('col-md-4'); } else if(count == 4){ children.addClass('col-md-3'); } }); |
[RBS Change] Quelques notes sur l’utilisation de l’extension change:media pour afficher des visuels
Utilisation de l’extension phpTal change:media
dans Change pour redimensionner les visuels appelés dans les templates et leur attribuer des classes spé.
Dans les templates de bloc, les visuels peuvent être appelés de la manière suivante :
1 |
<img change:media="document product/getDefaultVisual; format 'modules.responsive.frontoffice/medium'; class 'image img-responsive'" /> |
Il y a 2 paramètres qui vont nous intéresser plus particulièrement :
1 |
format 'modules.responsive.frontoffice/medium'; |
qui va servir à établir des dimensions hauteur et largeur maximales pour cette image (pour un redimensionnement côté serveur). Ici, « medium » est une clé que tu vas retrouver dans le fichier suivant : /modules/responsive/style/frontoffice.image.all.css
.
1 2 3 4 |
.medium{ max-width: 360px; max-height: 230px; } |
Cette clé peut tout à fait rsservir ailleurs, dans un autre bloc, pour afficher d’autres visuels qui auraient les mêmes dimensions. Et on peut créer d’autres clés pour s’en servir dans les templates.
Le 2ème paramètre important :
1 |
class 'image img-responsive' |
permet d’ajouter des classes à l’élément <img />
. Car ça ne se fait pas par l’intermédiaire d’un attribut class=""
.
[4:02 PM] Frank LANG: ok
[4:02 PM] Frank LANG: on a 15mn pour les dimensions d’image
[4:02 PM] Frank LANG: ouvre le template de la fp
[4:02 PM] Nicolas M: wep
[4:02 PM] Frank LANG: ceclui-ci (pour être sûr) : Y:\change30\manbow\themes\responsive\modules\catalog\templates\Catalog-Block-Declinedproduct-Success.all.all.html
[4:03 PM] Frank LANG: ton visuel principal est là
[4:03 PM] Frank LANG:
1 2 3 4 5 6 7 8 |
<div class="product-big" tal:attributes="id mainVisualBlockDOMId; style style"> <tal:block tal:condition="baseconfiguration/getActivatezoom"> <img change:media="document imageMini; format 'modules.manbow.frontoffice/pic780x761'; zoom 'true'; alt declinedproduct/getLabel"/> </tal:block> <tal:block tal:condition="not: baseconfiguration/getActivatezoom"> <img change:media="document imageMini; format 'modules.manbow.frontoffice/pic780x761'; alt declinedproduct/getLabel"/> </tal:block> </div> |
[4:03 PM] Frank LANG: (ligne 121)
[4:04 PM] Nicolas M: oui j’avais modifié la partie avec le pic780x761
[4:04 PM] Frank LANG: et c’est surtout cette ligne qui va nous intéresser
[4:04 PM] Nicolas M: mais ça a fait tout planter
[4:04 PM] Frank LANG:
1 |
<img change:media="document imageMini; format 'modules.manbow.frontoffice/pic780x761'; zoom 'true'; alt declinedproduct/getLabel"/> |
[4:05 PM] Frank LANG: l’attribut « format » fait référence à une classe CSS que tu vas retrouver dans un fichier « frontoffice.image.css » dans modules/manbow/style/
[4:06 PM] Frank LANG: Y:\change30\manbow\modules\manbow\style\frontoffice.image.all.css
[4:06 PM] Frank LANG: si tu cherches la classe « .pic780x761 »
[4:06 PM] Frank LANG: eh bin elle existe pas !!!
[4:06 PM] Frank LANG: mais y’en a déjà plein d’autres
[4:07 PM] Frank LANG: en gros, si on reprend la baliswe dans le template, tu pourrais mettre :
[4:07 PM] Frank LANG:
1 |
<img change:media="document imageMini; format 'modules.manbow.frontoffice/tototititutu'; zoom 'true'; alt declinedproduct/getLabel"/> |
[4:07 PM] Frank LANG: et dans « Y:\change30\manbow\modules\manbow\style\frontoffice.image.all.css »
[4:07 PM] Frank LANG: il faut ajouter :
[4:08 PM] Frank LANG:
1 2 3 4 |
.tototititutu { max-width: 410px; max-height: 360px; } |
[4:08 PM] Frank LANG: avec la largeur max et la hauteur max autorisées pour le redimensionnement qui va s’opérer côté serveur
Frank LANG·4:10 PM
faut faire un compile-all pour que les modifs soient prises en compte
[4:12 PM] Frank LANG: au passage c’est complètement con de nommer ce type de classes avec des dimensions
[4:12 PM] Frank LANG: autant définir peu de dimensions et avoir de sclasses qui s’appellent small, medium, big, avatar, …
[jQuery] Une navigation responsive par onglets en vue Desktop et accordéon en vue Mobile
HTML
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 |
<p class="desktop">desktop</p> <p class="mobile">mobile</p> <ul class="facet-nav"> <li class="facet-nav-item"> <a class="link level0" href="#">Lorem ipsum</a> <ul class="facet-nav-sublevel is-closed"> <li><a class="link" href="#">one</a></li> <li><a class="link" href="#">two</a></li> </ul> </li> <li class="facet-nav-item"> <a class="link level0" href="#">Dolor</a> <ul class="facet-nav-sublevel is-closed"> <li><a class="link" href="#">three</a></li> <li><a class="link" href="#">four</a></li> <li><a class="link" href="#">five</a></li> <li><a class="link" href="#">six</a></li> </ul> </li> <li class="facet-nav-item"> <a class="link level0" href="#">Sit amet</a> <ul class="facet-nav-sublevel is-closed"> <li><a class="link" href="#">seven</a></li> <li><a class="link" href="#">eight</a></li> <li><a class="link" href="#">nine</a></li> </ul> </li> </ul> <p>Lorem ipsum dolor sit amet ...</p> |
SASS
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 |
.facet-nav{ &-item{ > .link{ display: block; } } &-sublevel.is-closed{ display: none; } &-sublevel{ display: block; } } @media screen and (max-width: 767px){ } @media screen and (min-width: 768px){ .facet-nav{ display: table; &-item{ display: table-cell; } } } // skin .facet-nav{ border: 1px solid tomato; padding: 5px; &-item{ > .link{ border: 1px solid tomato; padding: 15px; &.is-active{ background: pink; } } } } @media screen and (max-width: 767px){ .desktop{display: none;} } @media screen and (min-width: 768px){ .mobile{display:none;} .facet-nav{ &-sublevel{ position: absolute; left: 0; width: 100%; background: pink; } } } |
jQuery
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 |
$(document).ready(function(){ var ulFacetNav = $('ul.facet-nav'); var liFacetNavItem = $('li.facet-nav-item'); var aFacetNavItemLevel0Link = $('a.level0'); var facetNavTargetElements = $('ul.facet-nav'); // la navigation ne doit pas se fermer au clic sur ces éléments // on réinitialise le DOM à l'état initial (pour refermer la nav, notamment) function DOMreset(){ ulFacetNav.removeAttr('style'); aFacetNavItemLevel0Link.each(function(){ $(this).removeClass('is-active'); }); $('ul.facet-nav-sublevel').each(function(){ $(this).addClass('is-closed'); }); } // au clic à l'extérieur de la nav, cette dernière se referme $(document).on('click', function(){ DOMreset(); }); // la navigation ne doit pas se fermer au clic sur ces éléments facetNavTargetElements.on('click', function(e){ e.stopPropagation(); }); // vue Mobile (nav accordion) enquire.register("screen and (max-width: 767px)", { match : function() { ulFacetNav.removeClass('is-desktop-nav').addClass('is-mobile-nav'); DOMreset(); liFacetNavItem.off('click', '.level0').on('click', '.level0', function(e){ $(this).toggleClass('is-active').next('ul.facet-nav-sublevel').toggleClass('is-closed'); e.preventDefault(); }); }, unmatch : function() {} }); // vue Desktop (nav tabs) enquire.register("screen and (min-width: 768px)", { match : function() { ulFacetNav.removeClass('is-mobile-nav').addClass('is-desktop-nav'); DOMreset(); liFacetNavItem.off('click', '.level0').on('click', '.level0', function(e){ if($(this).hasClass('is-active')){ DOMreset(); } else{ DOMreset(); $(this).toggleClass('is-active').next('ul.facet-nav-sublevel').toggleClass('is-closed'); var getOpenedFacetNavSublevelHeight = $(this).next('ul.facet-nav-sublevel').height(); ulFacetNav.css('margin-bottom', getOpenedFacetNavSublevelHeight); } e.preventDefault(); }); }, unmatch : function() {} }); }); |
[Git] Configurer un compte Git sur une install Ubuntu Server et générer une clé SSH d’utilisateur
…dans le cadre, notamment, d’une récupération de VM existante, le compte Git actuellement configuré doit être changé pour celui du développeur qui utilisera la VM.
L’idée ici est de supprimer le compte existant pour en créer un nouveau.
Si le repository est cloné via https
Supprimer le compte existant (le fichier sera regénéré à partir de vos login/mot-de-passe qui vous seront demandés la prochaine fois que vous essayerez d’accéder au Git) :
1 |
$ rm ~/.git-credentials |
Si le repository est cloné via SSH
Localiser le dossier ssh sur votre VM. Attention, c’est un dossier caché!
1 |
$ cd ~/.ssh |
Pour lister les clés existantes (fichiers de type id_rsa
):
1 |
$ ls -la |
Supprimer toutes les clés SSH existantes (ce ne sont pas les vôtres; vous ne voulez pas versionner des choses dans Git et que le nom d’utilisateur qui apparaisse dans les logs soit celui de quelqu’un d’autre a.k.a. l’utilisateur précédent de votre VM).
1 |
$ rm id_* |
Générer une nouvelle clé. Remarque : pour la génération de la clé SSH par défaut (commande $ ssh-keygen
), il vous sera demandé un nom et une passphrase. Laissez ces informations vides.
1 |
$ ssh-keygen |
Copier/coller la nouvelle clé SSH générée (fichier id_rsa.pub
). Pour l’afficher :
1 |
$ cat id_rsa.pub |
Dans l’interface Gitlab
- Profile settings > SSH keys > Add SSH key.
- Coller la clé SSH récupérée depuis votre VM Ubuntu.
- Si une clé SSH ne vous appartenant pas est listée, la supprimer pour ne conserver que celle que vous avez ajouté.
Editer la config Git
1 2 3 4 5 |
$ vim ~/.gitconfig <pre> <p>Définir la méthode de <em>push</em> (si Git vous le demande ...) :</p> <pre> [push] default = simple |
Stocker vos login/mot-de-passe afin qu’ils ne vous soient pas demandés à chacun de vos accès au Git :
1 |
[credential] helper = store |
[Ubuntu][Virtual Box][Réseau] Travailler en local sur une IP fixe
Monter 2 cartes réseau dans les paramètres de votre VM (sous Virtual Box)
Note pour moi-même:Cette conf permet de travailler en WiFi depuis la maison.
Récupérer l’IP de la carte eth1
Lancer la VM et à l’invite de commande, taper :
1 |
$ ifconfig eth1 |
Monter eth1 comme un lecteur réseau sous Windows (7 dans mon exemple)
- Sous Windows 7, afficher « Ordinateur ».
- Cliquer sur « Connecter un lecteur réseau ».
- Choisir un lecteur, puis dans le champ « Dossier », saisir le chemin vers votre machine virtuelle :
<IP_eth1>\<nom_de_votre_volume>
(chez moi :192.168.56.110\miaou
). - Cocher la case « Se reconnecter à l’ouverture de session ».
Ajouter l’IP de eth1 dans le host Windows.
Config pour le boulot
Une seule carte réseau: