My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

huangapple go评论69阅读模式
英文:

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

问题

我正在开发一个台球记分应用,使用HTML/CSS和JavaScript实现,存储在以下存储库中:
https://github.com/Zenilogix-Carl/Site

我一直在Windows和Chrome环境下进行开发,可以获得预期的输出,或者至少能够在该环境中诊断问题。我已经在一些朋友的iPhone上运行过它,并获得了非常不同(且有缺陷)的结果。我希望能找到有人帮助我识别和纠正影响iPhone的问题。

与我的问题相关的三个文件是:

  • NineBall.html
  • Billiards.js
  • styles.css

我附上了屏幕截图。请注意,在Chrome中,所有球都带有阴影;这是在BilliardBall类中定义的,并在BilliardBallWithState(都在Billiards.js中)中扩展,根据当前状态,可能会由NineBall.html中的updateBallState函数打开或关闭。初始状态应该在所有球上显示阴影,在Chrome中确实如此,但在iPhone上失败了。

此外,尽管在屏幕截图中没有反映出来,但似乎在iPhone上Cookie没有正常工作,因此我想知道是否我正确处理了它们 - 请查看NineBall.html中的onLoad函数和Billiards.js中的Preferences类。

我需要了解在不同浏览器之间可能不起作用/不一致支持的问题,并且需要做些什么才能使我的应用在Android(Chrome)和iPhone(可能是Safari)浏览器中正确运行。

Chrome屏幕截图(预期外观):

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?


iPhone屏幕截图(显示如上所述的异常):

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

编辑

添加了一个屏幕截图,以说明我正在追求的不同池球显示状态。这是在Chrome上,所以展示了我期望的情况。请注意,调暗状态可以选择与复选标记或“DEAD”文本组合,这两者都未被调暗,并具有阴影以帮助它们突出显示。我提到这一点是因为它与单独的组件元素可以或不能进行样式设置的方式相关。

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

英文:

I am working on a billiards scorekeeping app implemented in HTML/CSS/javascript at this repo:
https://github.com/Zenilogix-Carl/Site

I have been developing using Windows and Chrome, getting expected outputs or at least able to diagnose issues in that environment. I've seen it run on some friends' iPhones and I get very different (and flawed) results. I am hoping to find someone who can help me identify and correct the issues affecting iPhone.

The three files relevant to my issue are:

  • NineBall.html
  • Billiards.js
  • styles.css

I've attached screenshots below. Notice that in Chrome, all balls are rendered with a drop-shadow; this is defined in the BilliardBall class and extended into BilliardBallWithState (both in Billiards.js) and, depending on current state, may be turned on or off by function updateBallState in NineBall.html. Initial state should show the drop-shadow for all balls, which it does in Chrome, but fails to on iPhone.

class BilliardBall {
    constructor(number, size, allowForShadow) {
        var colors = ["yellow", "blue", "red", "purple", "orange", "green", "brown", "var(--ballBlack)"];
        var color = Number.isInteger(number) ? colors[(number - 1) % 8] : colors[0];
        var isStripe = Number.isInteger(number) ? (((number - 1) / 8) >= 1) : false;

        this.number = number;

        var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        svg.setAttribute("viewBox", allowForShadow ? "0 0 120 120" : "0 0 105 100");
        svg.setAttribute("width", size);
        svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
        var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
        this.ballGraphic = g;
        var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");

        if (isStripe) {
            circle.setAttribute("cx", 50);
            circle.setAttribute("cy", 50);
            circle.setAttribute("r", 48);
            circle.setAttribute("style", "fill: white;");
            g.appendChild(circle);

            var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
            path.setAttribute("d", "M 16 16 L 84 16 A 50 50 0 0 1 84 84 L 16 84  A 50 50 0 0 1 16 16 ");
            path.setAttribute("style", "fill: " + color + "; stroke-width: 1; stroke: grey;");
            g.appendChild(path);

            circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
            circle.setAttribute("cx", 50);
            circle.setAttribute("cy", 50);
            circle.setAttribute("r", 48);
            circle.setAttribute("style", "fill: transparent; stroke-width: 1; stroke: var(--ballOutline);");
            g.appendChild(circle);

        } else {
            circle.setAttribute("cx", 50);
            circle.setAttribute("cy", 50);
            circle.setAttribute("r", 48);
            circle.setAttribute("style", `fill: ${color}; stroke-width: 1; stroke: var(--ballOutline);`);
            g.appendChild(circle);
        }

        circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        circle.setAttribute("cx", 50);
        circle.setAttribute("cy", 50);
        circle.setAttribute("r", 27);
        circle.setAttribute("style", "fill: white; stroke-width: 1; stroke: grey;");
        g.appendChild(circle);
        var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
        text.setAttribute("x", 50);
        text.setAttribute("y", 53);
        text.setAttribute("text-anchor", "middle");
        text.setAttribute("dominant-baseline", "middle");
        text.setAttribute("font-weight", "bold");
        text.setAttribute("font-size", number > 9 ? "32px" : "40px");
        text.innerHTML = number;
        g.appendChild(text);
        svg.appendChild(g);

        this.element = svg;
    }
}

class BilliardBallWithState extends BilliardBall {

    constructor(number, size, clickFn, foulText) {
        super(number, size, true);

        const svg = this.element;
        svg.onclick = function () { clickFn(number)};
        let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
        text.setAttribute("style", "visibility: hidden;");
        text.classList.add("dropShadow");
        text.setAttribute("x", 50);
        text.setAttribute("y", 50);
        text.setAttribute("text-anchor", "middle");
        text.setAttribute("dominant-baseline", "middle");
        text.setAttribute("font-size", "30px");
        text.setAttribute("fill", "red");
        text.setAttribute("stroke-width", "1");
        text.setAttribute("stroke", "white");
        text.innerHTML = foulText;
        svg.appendChild(text);
        this.foulText = text;
        text = document.createElementNS("http://www.w3.org/2000/svg", "text");
        text.setAttribute("style", "visibility: hidden;");
        text.classList.add("dropShadow");
        text.setAttribute("x", 40);
        text.setAttribute("y", 90);
        text.setAttribute("font-size", "80px");
        text.setAttribute("fill", "green");
        text.setAttribute("stroke-width", "1");
        text.setAttribute("stroke", "white");
        text.innerHTML = "✔";
        svg.appendChild(text);
        this.checkMark = text;

        this.showNormal();
    }

    dimElement(elem, dim) {
        if (dim) {
            elem.classList.remove("dropShadow");
            elem.classList.add("dimmed");
        } else {
            elem.classList.add("dropShadow");
            elem.classList.remove("dimmed");
        }
    }

    showElement(elem, show) {
        elem.style.visibility = show ? "visible" : "hidden";
    }

    showNormal() {
        this.dimElement(this.ballGraphic, false);
        this.showElement(this.foulText, false);
        this.showElement(this.checkMark, false);
    }

    showPocketed(checked) {
        this.dimElement(this.ballGraphic, true);
        this.showElement(this.foulText, false);
        this.showElement(this.checkMark, checked);
    }

    showFoul() {
        this.dimElement(this.ballGraphic, true);
        this.showElement(this.foulText, true);
        this.showElement(this.checkMark, false);
    }
}

    function updateBallState(number) {
        const currentBallState = match.ballStates[number - 1];
        const ball = balls[number];

        switch (currentBallState) {
            case "normal":
                ball.showNormal();
                break;

            case "dead":
                ball.showFoul();
                break;

            default:
                ball.showPocketed(currentBallState === "won");
                break;
        }
    }

Also, although not reflecting in the screen caps, it seems that cookies are not working correctly on iPhone, so I am wondering if I am handling them correctly - see onLoad function in NineBall.html and Preferences class in Billiards.js.

I need to understand what I am doing that is not functional/uniformly supported across browsers and what I need to do for my app to run correctly in both Android (Chrome) and iPhone (presumably Safari) browsers.

Chrome screen-cap (expected appearance):

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?


iPhone screen-cap (shows anomaly as described above):

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

EDIT

Added one more screenshot to illustrate the different pool ball display states I am aiming for. This is on Chrome, so shows what I expect. Note how dimmed state is optionally combined with checkmark or "DEAD" text, both of which are not dimmed and have the drop-shadow to help them stand out. I mention this because of its relevance to the way individual component elements can or cannot be grouped for styling.

My app works in Chrome but not iPhone; what is my cross-browser compatibility issue?

答案1

得分: 2

更新 2:

在阅读了这个答案的评论并更深入了解了您对项目的目标后,我认为我已经找到了一个可接受的解决方案来解决您的问题。

似乎您将效果和叠加元素的概念合并在一起,但我认为它们是独立的问题。我下面提出的解决方案将解决效果问题。通过将自定义类应用于svg元素本身,您应该能够以浏览器安全的方式应用自定义效果。

但是,对于叠加元素,我认为最好的方法实际上是一个单独的元素覆盖了台球。从我所看到的情况来看,许多叠加元素都是重复使用的。我建议将重复使用的元素保存为站点资源,并应用于单独的HTML元素或作为伪元素的background-image。下面的代码尚未经过测试,但旨在更清晰地说明我的建议:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->
/* 通用样式。`position: relative;` 在父元素上需要设置正确的上下文以正确设置绝对定位的子元素 */
.ball {
  position: relative;
  width: 100px;
  height: 100px;
  padding: 10px;
}

/* 应用于.ball容器下的所有SVG元素 */
.ball svg {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background-color: green;
}

/* 对适用的SVG应用阴影 */
svg.dropShadow {
  box-shadow: 10px 5px 5px black;
}

/* 正确调暗适用的SVG */
svg.dimmed {
  filter: brightness(50%);
}

/* "Check" 在这种情况下是一个小的红色圆圈,叠加在调暗的SVG上 */
svg.check {
  position: absolute;
  top: 25%;
  left: 25%;
  background-color: red;
  z-index: 2;
  width: 50%;
  height: 50%;
}

<!-- language: lang-html -->
<div class="balls">
    <!-- 默认球的行为 -->
    <div class="ball">
        <svg class="dropShadow">
        </svg>
    </div>
    <!-- 调暗并检查球的行为 -->
    <div class="ball">
        <!-- `check`类将绝对定位此元素在球的前面 -->
        <svg class="check">
        </svg>
        <svg class="dimmed">
        </svg>
    </div>
</div>

<!-- end snippet -->

更新:

经过一番深入研究,我对这个答案在另一个Stack Overflow帖子中感到满意。

似乎g元素只是一个容器,不设计为应用样式。尽管大多数浏览器的工作方式都如预期,但直接将样式应用于g元素似乎并没有得到官方支持。正如我的初始答案所建议的那样,最佳做法似乎是将样式类移到父SVG元素。


我还没有解决您问题的“为什么”部分,但似乎在iOS上运行时,仍具有阴影的所有元素都在svg元素本身上设置了dropShadow类,而缺少阴影的元素,该类被添加到直接的子g元素上。

最初,我认为iOS WebKit对剪切SVG元素有非标准行为,但后来我意识到您的dimmed类在iPhone上也不起作用。

微调您的JavaScript以将类应用于svg元素本身而不是g元素应该是代码中几乎可以忽略的更改,这应该可以让您顺利前进。

我将继续研究这个问题...我想知道为什么iOS会表现出这种方式。

英文:

Update 2:

After reading the comments on this answer and learning more about your goals for the project, I believe I have found an acceptable solution to your problem.

It seems like you are grouping the idea of effects and overlaid elements together, but I believe they are separate issues. The solution I proposed below would take care of the effects problem. By applying custom classes to the svg element itself, you should be able to apply custom effects in a browser safe way.

However, for the overlaid elements, I think the best approach is actually a separate element that is overlaying the pool ball. From what I can see, a lot of your overlaid elements are reused. I would propose that the reused elements be saved as site resources, and applied to either a separate HTML element, or a background-image as a pseudo-element. The code below has not been tested, but is intended to give a more clear picture of my proposition:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

/* General styling. `position: relative;` needed on a parent to correctly set the context for an absolutely positioned child */
.ball {
  position: relative;
  width: 100px;
  height: 100px;
  padding: 10px;
}

/* Applies to all SVG elements under .ball container */
.ball svg {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background-color: green;
}

/* Applies drop shadow to the applicable SVG */
svg.dropShadow {
  box-shadow: 10px 5px 5px black;
}

/* Properly dims applicable SVGs */
svg.dimmed {
  filter: brightness(50%);
}

/* &quot;Check&quot; in this case is a small red circle that is overlaid on the dimmed SVG */
svg.check {
  position: absolute;
  top: 25%;
  left: 25%;
  background-color: red;
  z-index: 2;
  width: 50%;
  height: 50%;
}

<!-- language: lang-html -->

&lt;div class=&quot;balls&quot;&gt;
    &lt;!-- Default ball behavior --&gt;
    &lt;div class=&quot;ball&quot;&gt;
        &lt;svg class=&quot;dropShadow&quot;&gt;
        &lt;/svg&gt;
    &lt;/div&gt;
    &lt;!-- Dimmed and checked ball behavior --&gt;
    &lt;div class=&quot;ball&quot;&gt;
        &lt;!-- The `check` class would absolutely position this element over and in front of the ball itself --&gt;
        &lt;svg class=&quot;check&quot;&gt;
        &lt;/svg&gt;
        &lt;svg class=&quot;dimmed&quot;&gt;
        &lt;/svg&gt;
    &lt;/div&gt;
&lt;/div&gt;

<!-- end snippet -->

Update:

After a fair amount of digging, I am satisfied with this answer in another Stack Overflow post.

It seems that the g element is intended only to be a container, and is not designed to have style applied to it. While most browsers work as expected, applying styling to the g element directly does not appear to be officially supported functionality. As my initial answer suggests, it seems like the best course of action is to move your styling classes to the parent SVG element.


I don't yet have the why part of your issue, but it appears that when run on iOS, all of the elements that still have a drop shadow have the dropShadow class set on the svg element itself, whereas all the elements with missing drop shadows, the class is being added to the direct child g element.

Initially, I thought that iOS WebKit had nonstandard behavior for clipping SVG elements, but then I realized that your dimmed class also does not function on the iPhone.

Tweaking your JavaScript to apply the classes to the svg element itself, rather than the g element, should be a negligible change to your code that should get you on your way.

I'm going to keep looking into this... I would like to know why iOS behaves this way.

答案2

得分: 2

以下是翻译好的内容:

实际上,您可以将CSS样式应用于SVG <g>元素,这些样式将会被继承,但显然webkit不接受应用于SVG子元素的CSS滤镜

我可以在Epiphany/Web和Midori中重现这个渲染问题(在虚拟Linux Mint环境中运行)。

解决方法:父级<svg>使用CSS阴影,子元素使用SVG滤镜

正如Clint Warner建议的,您可以将CSS阴影应用于外部<svg>元素。

内部子元素可以使用本机SVG滤镜。

您可以添加一个包含本机SVG滤镜的不可见SVG,如下所示:

<svg height="0" width="0">
  <filter y="-50%" height="250%" id='dropshadowSvg' color-interpolation-filters="sRGB">
    <feDropShadow dx="5" dy="5" stdDeviation="5" flood-opacity="1" />
  </filter>
</svg>

然后通过CSS规则/内联样式应用它:

.dropShadowSVG {
    filter: url(#dropshadowSvg);
}

希望这有所帮助。

英文:

Actually you can apply css styles to SVG &lt;g&gt; elements that will can inherited – but apparently webkit does not accept css filters applied to SVG child elements.

I could reproduce this rendering issue in Epiphany/Web and Midori (running in a virtual Linux Mint environment).

Workaround: CSS drop shadow for parent &lt;svg&gt; SVG filter for child elements

As suggested by Clint Warner you can apply the CSS drop shadow to the outer &lt;svg&gt; elements.

Inner child elements can use a native SVG filter.

You could add an invisible svg containing a native svg filter like this:

&lt;svg height=&quot;0&quot; width=&quot;0&quot;&gt;
  &lt;filter y=&quot;-50%&quot; height=&quot;250%&quot; id=&#39;dropshadowSvg&#39; color-interpolation-filters=&quot;sRGB&quot;&gt;
    &lt;feDropShadow dx=&quot;5&quot; dy=&quot;5&quot; stdDeviation=&quot;5&quot; flood-opacity=&quot;1&quot; /&gt;
  &lt;/filter&gt;
&lt;/svg&gt;

and apply it via css rule/inline style

.dropShadowSVG {
    filter: url(#dropshadowSvg);
}

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

:root{
      --background: lightblue;
    --popupBackground: white;
    --foreground: black;
    --dropShadowFilter: drop-shadow(10px 10px 5px black);
    --ballOutline: grey;
    --ballBlack: black;
}

svg{
  overflow:visible;
  width:25%;
}


.dropShadowCSS {
    filter: var(--dropShadowFilter);
}

.dropShadowSVG {
    filter: url(#dropshadowSvg);
}

<!-- language: lang-html -->

&lt;svg height=&quot;0&quot; width=&quot;0&quot;&gt;
  &lt;filter y=&quot;-50%&quot; height=&quot;250%&quot; id=&#39;dropshadowSvg&#39; color-interpolation-filters=&quot;sRGB&quot;&gt;
    &lt;feDropShadow dx=&quot;5&quot; dy=&quot;5&quot; stdDeviation=&quot;5&quot; flood-opacity=&quot;1&quot; /&gt;
  &lt;/filter&gt;
&lt;/svg&gt;

&lt;div id=&quot;balls&quot; style=&quot;padding: 10px;&quot;&gt;
  &lt;svg viewBox=&quot;0 0 120 120&quot;  class=&quot;dropShadowCSS&quot;&gt;
    &lt;g&gt;
      &lt;circle cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;48&quot; style=&quot;fill: yellow; stroke-width: 1; stroke: var(--ballOutline);&quot;&gt;&lt;/circle&gt;
      &lt;circle cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;27&quot; style=&quot;fill: white; stroke-width: 1; stroke: grey;&quot;&gt;&lt;/circle&gt;&lt;text x=&quot;50&quot; y=&quot;53&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; font-weight=&quot;bold&quot; font-size=&quot;40px&quot;&gt;⏳&lt;/text&gt;
    &lt;/g&gt;&lt;text style=&quot;visibility: visible;&quot; class=&quot;dropShadow&quot; x=&quot;50&quot; y=&quot;75&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; font-size=&quot;30px&quot; fill=&quot;white&quot; stroke-width=&quot;1&quot; stroke=&quot;white&quot;&gt;&lt;/text&gt;&lt;text style=&quot;visibility: hidden;&quot; class=&quot;dropShadow&quot; x=&quot;40&quot; y=&quot;90&quot; font-size=&quot;80px&quot; fill=&quot;green&quot; stroke-width=&quot;1&quot; stroke=&quot;white&quot;&gt;✔&lt;/text&gt;
  &lt;/svg&gt;

  &lt;svg viewBox=&quot;0 0 120 120&quot;  class=&quot;dropShadowCSS&quot;&gt;
    &lt;g style=&quot;color:purple&quot;&gt;
      &lt;circle cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;48&quot; style=&quot;fill: #ccc; stroke-width: 1; stroke: grey ;&quot;&gt;
      &lt;/circle&gt;
      &lt;text class=&quot;dropShadowSVG&quot; x=&quot;50&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; font-size=&quot;20px&quot; font-weight=&quot;bold&quot; fill=&quot;currentColor&quot; stroke-width=&quot;1&quot;&gt;Time-out&lt;/text&gt;

    &lt;/g&gt;
  &lt;/svg&gt;
  
  &lt;svg viewBox=&quot;0 0 120 120&quot; class=&quot;dropShadowCSS&quot;&gt;
    &lt;g style=&quot;color:purple&quot;&gt;
      &lt;circle cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;48&quot; style=&quot;fill: #ccc; stroke-width: 1; stroke: grey ;&quot;&gt;
      &lt;/circle&gt;
      &lt;text class=&quot;dropShadowCSS&quot; x=&quot;50&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; font-size=&quot;20px&quot; font-weight=&quot;bold&quot; fill=&quot;currentColor&quot; stroke-width=&quot;1&quot;&gt;Time-out&lt;/text&gt;

    &lt;/g&gt;
  &lt;/svg&gt;
  

&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月24日 22:46:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324778.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定