Скрытие SVG влияет на другие стили SVG на той же странице

SVG загружается несколько раз на одной странице. SVG используется для графического представления значений. Представьте карту, на которой каждый регион показывает заданное значение с использованием цветового кода.

В каждом SVG, для каждой области динамически применяется класс CSS, чтобы соответствовать желаемому используемому шаблону заливки SVG.

Стили и шаблоны CSS определены в файле SVG. Вот пример:

  <svg height = "100" width = "100">
    <style>
    /*  */
    .striped-pain-1 {fill: url(#striped-pain-1);}
    /*  */
    </style>
    <defs>
        <pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
            <line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
        </pattern>
    </defs>

Проблема в том, что когда один из SVG скрыт (например, через display:none), все SVG оттуда до нижней части страницы теряют заливку узором.

Я сделал упрощенный Plunker, показывающий проблему.

https://plnkr.co/edit/F5TzOwDEzneHEW7PT3Ls?p=preview

Единственный способ, который я нашел, чтобы предотвратить это, - использовать другой шаблон ids для каждого SVG, но, поскольку все используют один и тот же файл, мне не нравится решение дублировать их все и переименовывать идентификаторы только для этого. Интересно, должно быть лучшее решение.

Итак, вы узнали, что не используйте display: none со ссылками. Вы можете сделать ширину и высоту SVG равными 0, вывести его за пределы экрана, установить видимость: скрыть или другие вещи, чтобы скрыть это без использования display: none

Robert Longson 28.03.2018 14:15

Спасибо, но не могли бы вы подробнее ответить? Почему использование display:none нарушает стиль? Я немного не понимаю, что происходит.

David Casillas 28.03.2018 15:58

display: ни у одного поддерева нет CSS. Без CSS никакие стили или атрибуты, сопоставленные стилям, работать не будут.

Robert Longson 28.03.2018 16:09

@RobertLongson, раз уж разыгрывается награда, вы можете добавить эти комментарии в ответ.

Kaiido 27.06.2019 15:20

Этот вопрос больше относится к структуре html, чем к отображению css. Тег DEFS предназначен для хранения структур, поэтому настоящая проблема заключается в том, чтобы поместить определение внутри тега div, которое будет скрыто. Кроме того, это дублированные идентификаторы, в чем и заключается суть вопроса. Ответ добавлен. w3schools.com/tags/att_global_id.aspdeveloper.mozilla.org/en-US/docs/Web/SVG/Element/defs

Benjamin 01.07.2019 22:53
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
8
5
2 180
3

Ответы 3

Я бы поместил шаблоны в другой элемент svg: <svg class = "defs">. Этот элемент svg может иметь position:absolute и очень маленькую ширину и высоту. Если вы добавите left: -200px;, этот элемент svg станет невидимым.

Также: если один элемент SVG имеет это правило css: .striped-pain-1 {fill: url(#striped-pain-1);}, вам не нужно добавлять его ко второму. Фактически, вы можете удалить элемент <style> из svg и добавить это правило в css.

Попробуйте: щелкните числа (1,2,3), чтобы скрыть или показать элементы svg.

let spans = Array.from(document.querySelectorAll("#commands span"))
let svgs = Array.from(document.querySelectorAll(".svgcontainer"))
spans.forEach((s,i) =>{
let n = 0;
s.addEventListener("click",(e)=>{
n++;
let thisSvg = svgs[i].querySelector("svg")
if (n%2 == 1){thisSvg.style.display = "none";
            }else{
             thisSvg.style.display = "block";}
})
})
svg {
  display:block;
}
.defs {
  position: absolute;
  left: -200px;
}
span {
  display: inline-block;
  width: 2em;
  height: 1em;
  border: 1px solid;
  text-align: center;
  cursor: pointer;
}
.svgcontainer {
  height: 100px;
  width: 100px;
  border: 1px solid;
  display: inline-block;
}
<p id = "commands"><span>1</span> <span>2</span> <span>3</span></p>

<svg class = "defs" width = "1" height = "1">
  <defs>
  		<pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
  			<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
  		</pattern>
    
      <pattern id = "striped-pain-2" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
  	</defs>
</svg>

<div class = "svgcontainer">
  <svg height = "100" width = "100">
  	<style>
  		/*  */
  		.striped-pain-1 {fill: url(#striped-pain-1);}
  		/*  */
  	</style>
    
    <circle class = "striped-pain-1" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 

</div>
<div class = "svgcontainer">
  <svg height = "100" width = "100">
   <!-- <style>
    		/*  */
    		.striped-pain-1 {fill: url(#striped-pain-1);}
    		/*  */
    </style>-->
    <!--<defs>
    	<pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>-->
    <circle class = "striped-pain-1" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>
<div class = "svgcontainer">
  <svg height = "100" width = "100">
    <style>
    		/*  */
    		.striped-pain-2 {fill: url(#striped-pain-2);}
    		/*  */
    </style>
    <circle class = "striped-pain-2" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

В конце концов я использовал именно такой подход. Я просто делюсь всем defs для всех svgs в невидимом элементе svg. Это также упростило мой код, чтобы избежать ненужного дублирования.

David Casillas 28.06.2019 16:16

Эта проблема возникает из-за того, что вы указали один и тот же id для двух разных элементов:

<pattern id = "striped-pain-1" в строках 52 и 69.

В HTML id должен быть уникальным.

The id attribute specifies a unique id for an HTML element (the value must be unique within the HTML document).

Замена дублированного id на уникальный решает проблему. См. Фрагмент ниже:

<!DOCTYPE html>
<html>

  <head>
    <meta charset = "utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href = "' + document.location + '" />');</script>
    <link rel = "stylesheet" href = "style.css" />
    <script data-require = "[email protected]" src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver = "1.5.11"></script>
    <script src = "app.js"></script>
    <script>
      function show(id) {
        document.getElementById('circle-' + id).style.display = 'block';
      }
      function hide(id) {
        document.getElementById('circle-' + id).style.display = 'none';
      }
      function reset() {
        document.getElementById('circle-1').style.display = 'block';
        document.getElementById('circle-2').style.display = 'block';
      }
    </script>
  </head>

<body ng-controller = "MainCtrl">
    
<div style = "padding:10px">
  <input type='button' onclick = "hide(1)" value = "Step 1: Click here to hide first circle. Second will loose style." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "show(1)" value = "Step 2: Click here to show first circle. Second will gain style." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "hide(2)" value = "Step 3: Click here to hide second circle. First is not affected." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "reset()" value = "Step 4: Reset." /> 
</div>

<div id = "circle-1" style = "padding:10px;border:solid grey 1px">
  Circle 1
  <svg height = "100" width = "100">
  	<style>
  		/*  */
  		.striped-pain-1 {fill: url(#striped-pain-1);}
  		/*  */
  	</style>
    <defs>
  		<pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
  			<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
  		</pattern>
  	</defs>
    <circle class = "striped-pain-1" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div id = "circle-2" style = "padding:10px;border:solid grey 1px">
  Circle 2
  <svg height = "100" width = "100">
    <style>
    		/*  */
    		.striped-pain-2 {fill: url(#striped-pain-2);}
    		/*  */
    </style>
    <defs>
    	<pattern id = "striped-pain-2" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>
    <circle class = "striped-pain-2" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div style = "padding:10px;border:solid grey 1px">
  Circle 3
  <svg height = "100" width = "100">
    <style>
    		/*  */
    		.striped-pain-3 {fill: url(#striped-pain-3);}
    		/*  */
    </style>
    <defs>
    	<pattern id = "striped-pain-3" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>
    <circle class = "striped-pain-3" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div style = "padding:10px;">
  These circles are SVGs. They have background applied as a pattern. The first two use clases with the same name, but the third not.
  Hidding the first SVG affects the second one, but hidding the second does not affect the first.
</div>


  </body>

</html>

Возможно, вы захотите избавиться от SVG и использовать более простой способ:

function show(id) {
  document.getElementById('circle-' + id).style.display = 'block';
}

function hide(id) {
  document.getElementById('circle-' + id).style.display = 'none';
}

function reset() {
  document.getElementById('circle-1').style.display = 'block';
  document.getElementById('circle-2').style.display = 'block';
}
#circle-1,
#circle-2,
#circle-3 {
  padding: 10px;
  border: solid grey 1px
}

.circle {
  display: inline-block;
  width: 80px;
  height: 80px;
  margin: 10px;
  border: solid 3px #000;
  border-radius: 55%;
  background: linear-gradient(135deg, #fff 20%, pink 21%, pink 50%, #fff 51%, #fff 71%, pink 72%) 0 0 / 8px 8px;
}


}
<div style = "padding:10px">
  <input type='button' onclick = "hide(1)" value = "Step 1: Click here to hide first circle. Second will loose style." />
</div>

<div style = "padding:10px">
  <input type='button' onclick = "show(1)" value = "Step 2: Click here to show first circle. Second will gain style." />
</div>

<div style = "padding:10px">
  <input type='button' onclick = "hide(2)" value = "Step 3: Click here to hide second circle. First is not affected." />
</div>

<div style = "padding:10px">
  <input type='button' onclick = "reset()" value = "Step 4: Reset." />
</div>

<div id = "circle-1">Circle 1 <span class = "circle"></span></div>
<div id = "circle-2">Circle 2 <span class = "circle"></span></div>
<div id = "circle-3">Circle 3 <span class = "circle"></span></div>

они не используют идентификатор дважды, они дважды ссылаются на один и тот же шаблон, пробой - это шаблоны в div, которые получают стиль "display: none", что делает шаблон несуществующим, поэтому на них нельзя ссылаться в следующем div .

Salix 01.07.2019 10:33

Извините, @Salix, но display: none только делает элемент невидимым для зрителя. Он НЕ удаляется из DOM, поэтому он все еще существует и, следовательно, все еще доступен из JS, CSS, HTML. @Kosh Очень, сделать уникальный идентификатор - правильный путь.

Rene van der Lende 03.07.2019 18:04

о да, я забыл, что я удалил второй шаблон 'stripped-pain-1' для тестирования, но если вы это сделаете, вы не сможете изменить шаблон из другого кружка div, он должен быть снаружи, что я имел в виду.

Salix 09.07.2019 04:06

Ваша проблема в том, что вы определяете путь SVG с id = "striped-pain-1". Два шага: во-первых, переместите из соединяемых элементов уникальный шаблон SVG для использования в качестве стиля, я использовал "# striped-pain-unique". Затем используйте в качестве URL-адреса для заполнения каждого элемента, который вам нужен.

.striped-pain-1 {fill: url(#striped-pain-unique);}

<!DOCTYPE html>
<html>

  <head>
    <meta charset = "utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href = "' + document.location + '" />');</script>
    <link rel = "stylesheet" href = "style.css" />
    <script data-require = "[email protected]" src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver = "1.5.11"></script>
    <script src = "app.js"></script>
    <script>
      function show(id) {
        document.getElementById('circle-' + id).style.display = 'block';
      }
      function hide(id) {
        document.getElementById('circle-' + id).style.display = 'none';
      }
      function reset() {
        document.getElementById('circle-1').style.display = 'block';
        document.getElementById('circle-2').style.display = 'block';
      }
    </script>
  </head>

<body ng-controller = "MainCtrl">
    
<div style = "padding:10px">
  <input type='button' onclick = "hide(1)" value = "Step 1: Click here to hide first circle. Second will loose style." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "show(1)" value = "Step 2: Click here to show first circle. Second will gain style." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "hide(2)" value = "Step 3: Click here to hide second circle. First is not affected." /> 
</div>

<div style = "padding:10px">
  <input type='button' onclick = "reset()" value = "Step 4: Reset." /> 
</div>

<svg height = "100" width = "100">
    <defs>
    	<pattern id = "striped-pain-unique" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>
</svg>

<div id = "circle-1" style = "padding:10px;border:solid grey 1px">
  Circle 1
  <svg height = "100" width = "100">
  	<style>
  		/*  */
  		.striped-pain-1 {fill: url(#striped-pain-unique);}
  		/*  */
  	</style>
    <defs>
  		<pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
  			<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
  		</pattern>
  	</defs>
    <circle class = "striped-pain-1" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div id = "circle-2" style = "padding:10px;border:solid grey 1px">
  Circle 2
  <svg height = "100" width = "100">
    <style>
    		/*  */
    		.striped-pain-1 {fill: url(#striped-pain-unique);}
    		/*  */
    </style>
    <defs>
    	<pattern id = "striped-pain-1" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>
    <circle class = "striped-pain-1" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div style = "padding:10px;border:solid grey 1px">
  Circle 3
  <svg height = "100" width = "100">
    <style>
    		/*  */
    		.striped-pain-2 {fill: url(#striped-pain-unique);}
    		/*  */
    </style>
    <defs>
    	<pattern id = "striped-pain-2" width = "4" height = "1" patternTransform = "rotate(45 0 0)" patternUnits = "userSpaceOnUse">
    		<line x1 = "0" y1 = "0" x2 = "0" y2 = "2" style = "stroke:#EABFD5; stroke-width:6"></line>
    	</pattern>
    </defs>
    <circle class = "striped-pain-2" cx = "50" cy = "50" r = "40" stroke = "black" stroke-width = "3" fill = "red" />
  </svg> 
</div>

<div style = "padding:10px;">
  These circles are SVGs. They have background applied as a pattern. The first two use clases with the same name, but the third not.
  Hidding the first SVG affects the second one, but hidding the second does not affect the first.
</div>


  </body>

</html>

Я забыл добавить: «Объекты, созданные внутри элемента <defs>, не отображаются напрямую», поэтому стили css начинают работать, когда уникальный блок def помещается за пределы toogle div. developer.mozilla.org/en-US/docs/Web/SVG/Element/defs

Benjamin 01.07.2019 22:58

Другие вопросы по теме