[英]SVG tspan incorrect position in Chrome/Edge but not in Firefox
[英]Incorrect SVG Mask Position On Load When Using Relative Positions (Chrome)
我正在做一個項目,我想在其中顯示圖像(模糊)並將“放大鏡”(帶有非模糊圖像的圓圈)放在感興趣的位置,用戶可以與之交互:
因此,圖像與 svg 元素一起放置在包裝器中。 該圖像應驅動 svg 的大小,因此我沒有使用view-box屬性。 SVG 絕對定位並覆蓋整個包裝器。 現在我可以使用相對定位在 svg 上放置元素。 然后我在 position 處放置一個圓圈,我希望放大鏡成為(仍然工作正常)。 作為蒙版,我在相同的 position(在蒙版元素內)創建了另一個圓圈,並在未模糊的圖像上使用了 css蒙版(#id) 。
這在 Firefox 上運行良好,但在 Chrome 上不會顯示掩碼。
只是,當我調整 window 的大小時,遮罩出現並且一切正常。
似乎掩碼元素未正確計算到其父元素。 面具放在左上角。 調整 window 的大小可修復此行為。
HTML
<div class="container">
<img src="https://source.unsplash.com/2Ts5HnA67k8/400x200">
<!-- SVG (purple) -->
<!-- Setting a viewbox can solve the Issue, but I would prefer not to. -->
<div class="wrapper">
<svg>
<!-- Define the Mask -->
<defs>
</defs>
<mask id="mask">
<circle r="20%" cx="43%" cy="20%" fill="white"></circle>
</mask>
<!-- The stroke of the masked cicle. -->
<circle r="20%" cx="43%" cy="20%" stroke="white" fill="transparent"></circle>
<!-- The Element we want to mask. -->
<image href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image>
</svg>
</div>
</div>
CSS
img {
filter: blur(4px);
}
image {
mask: url(#mask);
}
svg {
position: absolute;
left:0;
top:0;
width:100%;
height:100%;
如何在啟動時修復 chrome 的這種行為? 或者是否有解決方法,例如手動觸發遮罩層的重新計算?
我在這里創建了一個工作示例: https://codepen.io/Ukmasmu/pen/NWNrGoW
任何幫助將不勝感激:提前致謝:)
我認為問題來自 Chrome 的渲染引擎無法正確推斷自動調整大小的視圖框的尺寸。 如果您檢查<mask>
元素中的<circle>
元素和 hover 元素,您會發現它計算的尺寸不正確,而在其他瀏覽器中它解析為正確的像素值。
更簡單的方法是在加載<img>
元素時簡單地使用 JS 手動設置viewBox
屬性,以強制 Chrome 根據顯式 viewbox 值正確地重新呈現 SVG。
const img = document.querySelector('img'); const svg = document.querySelector('svg'); img.addEventListener('load', (e) => { svg.setAttribute('viewBox', `0 0 ${img.clientWidth} ${img.clientHeight}`) });
img { filter: blur(4px); } image { mask: url(#mask); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
<div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> </defs> <mask id="mask"> <circle r="20%" cx="43%" cy="20%" fill="white"></circle> </mask> <.-- The stroke of the masked cicle. --> <circle r="20%" cx="43%" cy="20%" stroke="white" fill="transparent"></circle> <!-- The Element we want to mask. --> <image href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>
這絕對是一個錯誤,可能是bug=330815 。
強制重新繪制蒙版將解決此問題。
這可以通過在頁面加載時進行簡單的 class 設置來實現,該設置將強制display
或position
更改:
onload = evt => document.body.classList.add('loaded');
/* Chrome hack around bug 330815 */.loaded mask { display: block; } img { filter: blur(4px); } image { mask: url("#mask"); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
<div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> <mask id="mask"> <circle r="20%" cx="43%" cy="20%" fill="white"/> </mask> </defs> <.-- The stroke of the masked cicle. --> <circle r="20%" cx="43%" cy="20%" stroke="white" fill="none"/> <!-- The Element we want to mask. --> <image mask="url(#mask)" href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>
如果你真的想要沒有 JS 的東西,你也可以通過 SMIL 實現同樣的破解。
例如,在<mask>
中為<use>
的href
值設置動畫似乎可以做到這一點:
img { filter: blur(4px); } image { mask: url("#mask"); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
<div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> <circle r="20%" cx="43%" cy="20%" id="circle"/> <mask id="mask"> <use x="0" href="#circle" fill="white"> <.-- Chrome hack around bug 330815 --> <animate attributeName="href" to="#circle" begin="0" dur="0s"/> </use> </mask> </defs> <.-- The stroke of the masked cicle. --> <use href="#circle" fill="transparent" stroke="white"/> <!-- The Element we want to mask. --> <image mask="url(#mask)" href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.