Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

SVG sprite. Неправильное позиционирование в хроме

#svg #gulp #svg_спрайт


Создаю спрайт с помощью gulp (плагин gulp-svg-sprites). В Mozilla отображается нормально,
в хроме открываю - всё сдвинуто. 

Если из конечного svg я генерирую png-спрайт (плагин gulp-svg2png), и подключаю его
вместо svg, то во всех браузерах отображается нормально. т.е. я так понимаю это что-то
связано именно из интерпретацией браузером.

Как исправить? 

Пример моего спрайта после галпа есть здесь . При изменении размеров бегунком в хроме
этот баг тоже можно увидеть (хорошо заметно при максимальном увеличении, на белых -
когда инвертировать фон).

В мозиле всё нормально.

P.S. Обновил спрайт - установил, чтобы viewBox у всех элементов начинался с "0 0.
не помогло.

Настройки gulp:

gulp.task('svg-sprites:build', function () {
  return gulp.src(options.theme.img_svg_src + '*.svg')
      .pipe(svgSprite())
      .pipe(gulp.dest(options.theme.img_src + 'dict'))
      .pipe(filter(options.theme.img_src + 'dict/svg/*.svg')) 
      .pipe(gulp.dest(options.theme.img_src + 'dict'));
});

    


Ответы

Ответ 1



Короткий ответ Удалите атрибут viewBox="0 0 41 2023" из SVG. Впрочем, остальные viewBox тоже можете удалить. Можно сделать это автоматически с помощью svgo (плагин removeViewBox). Длинный ответ Это похоже на баг Chrome, связанный с расчетом background-size, когда background-size по горизонтали не кратен ширине viewBox в SVG. Смотрите, у вас background-size задается в em: 4.1em 202.3em (sprite.css:5). А изменение размеров картинок задается через font-size от 2 до 14 px. Исходное значение font-size равно 10px, поэтому при открытии страницы размер фона в пикселях получается 41x2023 px, как раз как viewBox в SVG. Можно прописать background-size: 41px 2023px и все останется по-прежнему. Но если указать на пиксель меньше: background-size: 40px 2023px, мы увидим смещение по вертикали. Хотя, казалось бы, картинка должна стать просто немного уже. Поэтому при изменении шрифта все едет. Если задать размер шрифта 11px, то ширина фона получится 4.1em * 11px = 45.1px, а это не кратно 41 (ширина исходного viewBox). Следующее значение шрифта, при котором все показывается нормально - 20px: размер background-size по горизонтали становится 82px, что кратно 41. Я точно не берусь описать все особенности этого бага (иногда он проявляется, иногда нет), но суть в том, что решение простое: удалите атрибут viewBox="0 0 41 2023" из SVG. Впрочем, остальные viewBox тоже можете удалить. Можно сделать это автоматически с помощью svgo (плагин removeViewBox). Пример для gulp: gulp.task('remove-viewbox', function() { var svgmin = require('gulp-svgmin'); return gulp.src('src/*.svg') .pipe(svgmin({ plugins: [ {removeViewBox: true} ] })) .pipe(gulp.dest('dest/')); });

Ответ 2



Вы наверное уже догадались, что в Chrome видите вместе с основной иконкой низ предыдущей иконки. Причин тут может быть много, но основных две: У каждого браузера свои стили, поэтому лучше их сбросить отдельным файлом reset.css от Эрика Майера, либо применить Normalize.css, почитайте перевод статьи здесь. Вторая, основная причина - подбор иконок с разными пропорциями. У одних width="7" height="7" viewBox="0 0 7 7, у других viewBox="231 233 38 34 Видите, тут пришлось двигать иконку с помощью viewBox. И дальше, если посмотреть, запустите SVG файл спрайта локально, то увидите большие пробелы, это просто иконки не попадают в зону видимости. Чтобы избежать таких рисков и непоняток, может быть проще найти SVG иконки с одинаковыми атрибутами. Таких подборок очень много в сети, где прямо они отсортированы по размерам 32x32; 64x64; 128x128...

Ответ 3



Вариант 1: удаление у исходных файлов ViewBox Используйте плагины gulp-imagemin и imagemin-svgo для удаление ViewBox: var gulp = require('gulp'), svg-sprites = require('gulp-svg-sprites'), imagemin = require('gulp-imagemin'), imageminSvgo = require('imagemin-svgo'); gulp.task('svg-sprites:build', function () { return gulp.src(options.theme.img_svg_src + '*.svg') .pipe(imagemin([ imageminSvgo({ plugins: [ {removeViewBox: true} ] }) ])) .pipe(svgSprite()) .pipe(gulp.dest(options.theme.img_src + 'dict')) .pipe(filter(options.theme.img_src + 'dict/svg/*.svg')) .pipe(gulp.dest(options.theme.img_src + 'dict')); }); Вариант 2: заменить SVG-спрайт на иконочный шрифт Предпочтительней было бы использование иконичного шрифта вместо спрайтов. И у этого метода есть ряд преимуществ: Более меньший вес шрифта, чем спрайта; Гибкость стилизации через CSS; Меньший вес CSS. Для генерации иконочного шрифта я бы посоветовал такую комбинацию: // Generate icon font gulp.task('iconfont', function() { var fontName = 'icon-font', cssClass = 'i'; // Исходные SVG-файлы gulp.src(['./fonts/icon-font/*.svg']) .pipe(iconfontCss({ fontName: fontName, cssClass: cssClass, path: './styl/mixins/icon-font.styl', targetPath: '../../styl/components/font/icon-font.styl', fontPath: '../fonts/' })) .pipe(iconfont({ fontName: fontName, prependUnicode: true, normalize: true, formats: ['svg','ttf','woff','woff2'] })) .pipe(gulp.dest('./public/fonts/')); }); Миски для стилей, который берется из этой строки path: './styl/mixins/icon-font.styl' будет выглядеть так: @font-face font-family "<%= fontName %>" src: url('<%= fontPath %><%= fontName %>.woff2') format('woff2'), url('<%= fontPath %><%= fontName %>.woff') format('woff'), url('<%= fontPath %><%= fontName %>.ttf') format('truetype'), url('<%= fontPath %><%= fontName %>.svg#<%= fontName %>') format('svg') [class*="i-"] position relative display inline-block width 1em height 1em &:before font 14px '<%= fontName %>' font-size inherit text-rendering auto speak none font-variant normal text-transform none color inherit position absolute top 50% left 50% transform translate(-50%, -50%) <% _.each(glyphs, function(glyph) { %> .<%= cssClass %>-<%= glyph.fileName %>:before content "\<%= glyph.codePoint %>" <% }); %> После генерации шрифта все, что вам нужно будет сделать, это подключить сгенированный CSS к вашему сайту или инглудить его к главному CSS-файлу, а затем использовать таким образом:

Ответ 4



Я взял ваш спрайт и для наглядности немного отформатировал код, не изменяя его сущности. Обратите внимание, что за вертикальные пробелы между иконками отвечают атрибуты viewport, которые обычно не указывают, так как по умолчанию они x="0" y="0" - это верхний левый угол. В вашем варианте для первой иконки y="0", для второй иконки - y="32", далее y="64" То есть вертикальное позиционирование исключительно зависит от этих параметров. Первый вариант решения - необходимо увеличить зазоры между иконками, то есть увеличитьY Внизу пример, как было, видите практически нет зазора между иконками. Во втором примере зазор увеличен на 8px; y=0;40;80;120 Учитывая, что в вашем варианте вы жестко привязаны к позиционированию иконок внутри спрайта и как выясняется это может приводить к непредсказуемым эффектам, можно предложить - Второй вариант сделать классический спрайт, используя теги и команды вызова из спрайта. viewBox="0 0 32 32" width="32" height="32" > viewBox="0 0 32 32" width="32" height="32" > Такой вариант позволяет позиционировать иконки, используя x,y координаты в команде и выглядит одинаково во всех браузерах. Вариант с иконками в одном блоке, с минимальными отступами viewBox="0 0 32 32" width="32" height="32" > viewBox="0 0 32 32" width="32" height="32" > Красная рамка - это граница SVG, только для просмотра, её можно убрать - border:1px solid red; я использовал её для настройки отступов. UPD 23.02.2017 В дополнение блок SVG социальных иконок с рабочими ссылками на соцсети. Работоспособность проверена в: chrome, FF, Opera, Yandex viewBox="0 0 32 32" width="32" height="32" > viewBox="0 0 32 32" width="32" height="32" >

Комментариев нет:

Отправить комментарий