汉堡图标:尽管像素对齐,但面包+汉堡的大小相同?

Posted

技术标签:

【中文标题】汉堡图标:尽管像素对齐,但面包+汉堡的大小相同?【英文标题】:Hamburger icon: buns+burger same size despite pixel alignment? 【发布时间】:2022-01-15 10:33:52 【问题描述】:

问题:中间的条比其他条高一个像素。这 不是 因为我的 css 错误,这是因为浏览器将矩形的边缘与像素网格对齐。

我尝试了几种不同的方法来制作汉堡图标:

    绝对定位一些带有背景颜色的 div。

    内嵌 svg 标签

    svg 作为背景图片

    带有顶部/底部边框和条形的背景颜色的单个 div,以及用于空格的填充和 background-clip: content-box;

所有这些方法都有相同的问题:

在某些缩放级别/大小下,图标看起来很糟糕,因为三个矩形的大小并不完全相同。它们有时大小不同,因为浏览器喜欢将矩形的边缘与像素网格对齐。

我当然希望矩形之间的两个空间也具有相同的厚度。

我知道这是为了妥协,图标必须是 5 像素高的倍数。或者,如果您可以在交替断点处将空间扩展一个像素,而不是扩展条形时,那么它可以是不同大小的 2 倍或 3 倍。

那么有什么诀窍呢?

网络字体是否可以使用提示来使所有三个矩形都获得相同数量的厚度像素,而不管大小/分辨率/缩放如何?

我可以做一些 CSS 数学运算吗?

我真的希望我不必让 javascript 尝试检测缩放级别的变化。

编辑:现场演示

var hamburgerIconEl = document.getElementById('hamburgerIcon');
var fontSizeEl = document.getElementById('fontSize');
fontSizeEl.addEventListener('input', function (e) 
    hamburgerIconEl.style.fontSize = '' + (8 + parseFloat(fontSizeEl.value) / 100) + 'px';
);
    .body 
        background: white;
    
    #hamburgerIcon 
        box-sizing: border-box;
        display: inline-block;
        height: 1.7ex;
        width: 2.04ex;
        border-width: .34ex 0;
        border-style: solid;
        border-color: black;
        background-clip: content-box;
        padding: .34ex 0;
        background-color: black;
    
<p>Change the font size, watch the hamburger icon, see how there are a lot of sizes in which the bars don't all have the same thickness and/or spacing.</p>
<div>
  <input type="range" id="fontSize" min="0" max="1000" value="0">
  <label for="volume">Font Size</label>
</div>
<div>
    <div id="hamburgerIcon" style="font-size: 8px"></div> Menu
</div>

【问题讨论】:

您可以发布您的代码以便我们提供帮助吗?我们不知道你在做什么。 我没有任何代码可以产生所需的结果。如果您知道方法,请发布。 我添加了一个实时代码 sn-p,它带有一个可以缩放图标的滑块,因此您可以看到它在某些尺寸上看起来不错,而在其他尺寸下看起来很差。请注意,这取决于屏幕分辨率/缩放级别,因此我不能只选择适合我屏幕的尺寸并期望它在任何地方看起来都不错。 显然你没有产生你想要的结果的代码......或者你不会寻求帮助:) sn-p 是我所要求的,因为我们可以测试现在就可以了。 【参考方案1】:

现在,我还没有看到您的内联 SVG,但问题是您将线条放置得太靠近 SVG 的边缘吗?如果是这样,顶线和底线的一部分会缝得更细,因为它们很可爱。

var hamburgerIconEl = document.getElementById('hamburgerIcon');
var fontSizeEl = document.getElementById('fontSize');
fontSizeEl.addEventListener('input', function (e) 
  hamburgerIconEl.style.fontSize = '' + (8 + parseFloat(fontSizeEl.value) / 100) + 'px';
);
svg 
  height: 2em;
  width: 2em;
  font-size: 8px;
<div>
  <input type="range" id="fontSize" min="0" max="1000" value="0">
  <label for="volume">Font Size</label>
</div>
<div>
  <svg viewBox="0 0 10 10" id="hamburgerIcon">
    <path d="M 1 3 H 8 M 1 5 H 8 M 1 7 H 8" fill="none" stroke="black" stroke- />
  </svg>
</div>

【讨论】:

哦,这是一个改进 :) 到目前为止,这看起来是 chrome 中最好的。但我仍然希望找到一种方法让高度自动变得如此自动,因此不需要抗锯齿。【参考方案2】:

系统在处理部分像素方面确实存在困难——一个 CSS 像素可以映射到现代设备上的多个屏幕像素。

当试图显示一个像素的一小部分时,必须决定是否将屏幕像素留在“后面”。

绘制汉堡包的一种稍微简单的方法,使用背景图像线性渐变,消除了中间条有时不居中的问题。然而,在某些奇怪的情况下,中间的条与其他两个条的高度并不完全相同。

var hamburgerIconEl = document.getElementById('hamburgerIcon');
var fontSizeEl = document.getElementById('fontSize');
const label = document.querySelector('label');
fontSizeEl.addEventListener('input', function(e) 
  hamburgerIconEl.style.fontSize = '' + (8 + parseFloat(fontSizeEl.value) / 100) + 'px';
  label.innerhtml = 'Font Size = ' + hamburgerIconEl.style.fontSize;
);
#hamburgerIcon 
  display: inline-block;
  padding: 0;
  margin: 0;
  height: 1.7ex;
  width: 2.05ex;
  background-image: linear-gradient(black 0 20%, transparent 20% 40%, black 40% 60%, transparent 60% 80%, black 80% 100%);
<div>
  <input type="range" id="fontSize" min="0" max="1000" value="0">
  <label for="volume">Font Size</label>
</div>
<div id="hamburgerIcon"></div>

【讨论】:

哦,部分归功于比我的更简单、更对称。【参考方案3】:

这是一个非常棘手的问题。不同的浏览器以不同的方式舍入半像素并具有不同的缩放级别,因此很难设置在所有浏览器和缩放中都能很好缩放的大小。

如果您还没有找到,可以查看this question。

您可以尝试使用&lt;canvas&gt; 元素来绘制形状。这更符合我的经验。

例子:

const canvas = document.getElementById('canvas')
if (canvas.getContext) 
    var ctx = canvas.getContext('2d');
    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, 30, 1);
    ctx.clearRect(0, 1, 30, 2);
    ctx.fillRect(0, 3, 30, 1);    
    ctx.clearRect(0, 4, 30, 2);
    ctx.fillRect(0, 6, 30, 1);
  
.container 
  padding: 10px 20px;
  display: block;


.burger 
  background-color: green;
  background-clip: content-box;
  padding-top: 2px;
  padding-bottom: 2px;
  border-top: 2px solid green;
  border-bottom: 2px solid green;
  height: 2px;
  width: 30px;
<div class="container">
  <h5>Div with bordrder</h5>
  <div class="burger one"></div>
</div>


<div class="container">
  <h5>Canvas</h5>
  <canvas id="canvas"></canvas>
</div>

【讨论】:

【参考方案4】:

这是一个 javascript 解决方案。它在 Chrome 上非常适合我,但在我的 iPad 上却以创造性的方式失败了。

var hamburgerIconEl = document.getElementById('hamburgerIcon');
var fontSizeEl = document.getElementById('fontSizeSlider');
var dppxEl = document.getElementById('dppx');
function updateHamburgerIcon () 
    var height = parseFloat(getComputedStyle(hamburgerIconEl).height);
    var physPx = height * window.devicePixelRatio;
    var sparePhysPx = physPx % 5;
    var sparePx = sparePhysPx / window.devicePixelRatio;
    hamburgerIconEl.style.setProperty('--sparePx', '' + sparePx + 'px');

fontSizeEl.addEventListener('input', function (e) 
    hamburgerIconEl.parentElement.style.fontSize = '' + (8 + parseFloat(fontSizeEl.value) / 50) + 'px';
    updateHamburgerIcon();
);
updateHamburgerIcon();
function onResolutionChange (cb) 
    dppxEl.innerText = '' + window.devicePixelRatio;
    matchMedia('(resolution: ' + window.devicePixelRatio + 'dppx)')
        .addEventListener("change",
            function (e) 
                onResolutionChange(cb);
                cb(e);
            ,  once: true );

onResolutionChange(updateHamburgerIcon);
.body 
    background: white;
    color: black;

#fontSizeSlider 
    width: 100%;

#hamburgerIcon 
    display: inline-block;
    height: .75em;
    width: .88em;
    background-color: transparent;
    background-position: 50% 100%;
    background-repeat: no-repeat;
    background-image: linear-gradient(black 0 20%, transparent 20% 40%, black 40% 60%, transparent 60% 80%, black 80% 100%);
    --sparePx: 0px;
    background-size: auto calc(.75em - var(--sparePx));
<p>Try the size slider below, and also changing your zoom (current dppx: <span id="dppx"></span>)</p>
<div>
    <input type="range" id="fontSizeSlider" min="0" max="1000" value="0">
</div>
<div style="font-size: 8px">
    <div id="hamburgerIcon"></div> Menu
</div>

【讨论】:

以上是关于汉堡图标:尽管像素对齐,但面包+汉堡的大小相同?的主要内容,如果未能解决你的问题,请参考以下文章

单击汉堡图标并调整窗口大小后,Navbar消失(我不希望它隐藏)

Xamarin Forms Shell 是不是有删除导航栏但保留汉堡图标的方法?

三行菜单?纳维康?抽屉?菜单图标?侧扫?三条纹?汉堡包? [关闭]

工具栏导航汉堡图标丢失

Vuetify 2.0 中未显示汉堡包图标

CF1207A