Differences to traditional browsers
HTML5, CSS3 and JavaScript are very large standards. We have identified the subset of the standards that are best suited for the creation of game user interfaces. Removing some of the properties/tags allows us to concentrate on the best way to develop UI and provide the maximum performance for those code paths.
For a complete list of what’s supported, refer to the dedicated section for HTML elements, CSS Properties, CSS Selectors, JavaScript DOM Events, SVG Support.
Each new Prysm version expands the supported features and improves compatibility with classic web browsers.
Flexbox layout
Currently, Prysm has full support for the FlexBox layout, which is the most powerful yet simplest layout standard supported by CSS. FlexBox allows creating responsive UIs in a more intuitive way than the classic “Box” HTML layout. For more information on FlexBox, please consult the documentation of the Visual Editor or the following links:
- https://css-tricks.com/snippets/css/a-guide-to-flexbox/
- https://learnlayout.com/flexbox.html
- https://philipwalton.github.io/solved-by-flexbox/demos/holy-grail/
display: flex;
and flex order column, even if their display is block
and box-sizing: border-box;
.flex-basis: content
value. Since flex-basis: auto
may fall back to resolving as flex-basis: content
when used next to sibling elements with basis values in percentages, we recommend that for sibling elements you don’t combine basis in percentages with auto. If you specify flex-basis
for elements - either use percentages for all siblings or prefer other unit type combinations.Media Queries
Prysm does not support the media types that are listed in the standard as print
, screen
etc., because it always displays in the screen
media.
// INVALID IN Prysm - screen is implied
/*@media screen and (min-width: 1280px) and (min-height=720px)
{
.mybutton
{
background-color: blue;
}
}*/
// OK!
@media (min-width: 1280px) and (min-height: 720px)
{
.mybutton
{
background-color: blue;
}
}
Prysm also supports adding whole CSS files conditionally under the “media” rules. It can be achieved with the following syntax:
<link rel="stylesheet" media="(orientation: portrait) and (min-width: 1280px)" href="sheet.css" />
All the rules from sheet.css will be activated/deactivated according to the expression in the media attribute. Note that @font-face
and @keyframes
rules are always added. The media only applies to CSS rulesets.
<link>
elements created with it from the HTML file. Adding/removing the media attribute from an already created <link>
element from JavaScript will not have any effect.Ordering of @keyframes
and @font-face
at-rules
Currently, we do not support ordering of @keyframes
and @font-face
rules. They will be ordered based on the initial order of loading the stylesheets. When using them inside media queries, the last activated @font-face
or @keyframes
will take precedence regardless of their position in the stylesheet.
For more information on ordering of @keyframes
rules refer to the dedicated section for ordering of keyframe rules.
For more information on media queries refer to the dedicated section for Media Queries.
Differences with the standard
Prysm deviates from the HTML/CSS standard in some feature implementations. This is done in cases where we feel that a slightly different implementation will give better performance or a more intuitive workflow. For this reason, it is possible that the same page rendered in Prysm may look different when rendered in a web browser.
Layout differences
The most prominent difference compared to a traditional browser is that every element in Prysm has display: flex;
and box-sizing: border-box;
by default. These are not the default values in the HTML5 standard but are more convenient for UI development.
As Prysm only supports flex layout display: inline
and display: block
are simulated with flex by changing the flex-direction. There is a difference between the simulated and actual behaviour for these properties so their use is not recommended when attempting to make pages that look the same as a traditional browser. Since the default display for many elements is either block, inline, or inline-block if the defaults aren’t changed there might be some unexpected differences in layout.
The default value for flex-shrink
is 0 instead of 1.
<p>
and <span>
Elements are display: flex
and flex-direction: row
by default in Cohtml instead of block and inline respectively.
For min-width
and min-height
the value of auto
is always treated as 0.
There will be additional layout(and other) differences if <!DOCTYPE html>
is missing as browsers will treat pages without <!DOCTYPE html>
as legacy pages and will have legacy behavior for various features.
SVG sizing - Auto-sizing of containers with inline SVG children is not supported, so containers should have concrete sizes.
The <html>
element has a width of 100vw
and height of 100vh
Another thing that might cause some layout differences is that some less common HTML elements might be missing their default styles e.g. h1
-h6
, textarea
, blockquote
, figure
etc. However, they can be found here https://html.spec.whatwg.org/multipage/rendering.html and applied to achieve consistency.
FlexBox on all elements makes their layout more intuitive. The border-box
sizing means that all width
and height
CSS properties include the padding and border of the element.
The ResizeObserver
API reports the changes made to the observed elements with up to 2 frames delay.
The last difference is linked to the usage of % (percent) on absolute-positioned elements. By standard percentages are resolved against the first positioned parent of an element. In Prysm they are resolved against the direct parent. This is a measure that improves performance and is more intuitive.
Overall to achieve the same visuals in a traditional browser:
- Use
display: flex
everywhere. - Use
box-sizing: border-box
. - Explicitly set flex-shrink to the desired value.
- Wrap SVGs in containers with concrete sizes.
- If a default style of a less common HTML element is different, find the desired styles here https://html.spec.whatwg.org/multipage/rendering.html.
Text differences
Text is one of the areas where Prysm departs from the CSS standard. The HTML standard requires breaking the layout of an in-line box in lines, wrapping the text and allowing for other elements to exist inside. In Prysm we implement single text runs (along with the style) as text boxes laid out with flex-row with wrapping. This has several advantages:
- Better performance as it doesn’t require a change in the layout tree mid-layout
- Rendering can be optimized better In practice the difference shouldn’t have a significant impact on the authoring or visual look of the page.
Break (<br>
) differences
Currently, <br>
tags work only when inside a text run. We have disabled <br>
between tags because it leads to bad HTML design and is error-prone. The same result can be achieved much more cleanly with flex items and coefficients.
Window Error event specifics
The HTML standard defines a different number of arguments for the window.onerror = (message, source, lineno, colno, error) =>{};
and window.addEventListener("error", (event) =>{};
handlers. However, the window.onerror
handler in Prysm receives a single event
object exactly like the window.addEventListener("error", ...);
handler.
window.onerror
and window.addEventListener("error", ...)
calls are available only on platforms that use the V8 VM.Custom CSS properties
Color matrix filter
The filter
CSS property allows the usage of predefined filters such as blur
, contrast
and others. Most effects can be achieved with the standard filters, but in case something custom is needed Prysm supports the custom coh-color-matrix
filter which accepts a 4x5 color matrix in the form of 20 numbers like so:
.visualStyle {
filter: coh-color-matrix(0.56, 0, 0, 0, 0.161, 0, 0.56, 0, 0, 0.196, 0, 0, 0.56, 0, 0.302, 0, 0, 0, 1, 0);
}
The color matrix can be animated with CSS animations. The animation is done by linear interpolation of each matrix component.
The resulting color is computed using the following equation (assuming the input is the RGBA
vector):
Directional blur filter
The filter
CSS property supports the blur
filter, which is limited to applying only omnidirectional blur
. Prysm introduces the custom filter coh-axis-blur
, which allows blurring per axis. The filter has two parameters: blur
values for the X and the Y axes. The directional blur
can be animated with CSS animations.
The following CSS code will cause the elements with class visualStyle
to be blurred both in the X and Y directions. However, the blur
for the Y direction will be stronger.
.visualStyle {
filter: coh-axis-blur(2px 5px);
}
Specifying blur
only for one axis (direction) is possible and happens by plugging the 0
value for the other axis.
.visualStyle {
filter: coh-axis-blur(0px 5px);
}
Here is a comparison between the standard blur
filter and the coh-axis-blur
one:
Parent nodes
Properties parentNode
and parentElement
on the nodes are not guaranteed to return the parent when it is not present in the DOM tree and is not referenced from JS.
Events
Event listener callback
The event.target
and event.currentTarget
properties are only valid in the call stack in which the event handler was called. If you store the event object and use it after it has been fired, its target
and currentTarget
properties will be null.
Mouse events
The mouseenter
, mouseover
, mouseleave
and mouseout
events will not fire unless a mouse move or scroll event is passed to the Cohtml API. The same rule applies to updating the currently hovered element - it will only be updated by mouse move or scroll events firing inside the Cohtml API.
Checking for elements under the mouse pointer and firing the corresponding JS events every frame can result in suboptimal performance. If you need this behavior, you can achieve it by sending mouse events using the cohtml::View::MouseEvent
API every frame with the current mouse pointer position:
// Native
cohtml::MouseEventData mouseData;
mouseData.X = current_mouse_position_x;
mouseData.Y = current_mouse_position_y;
m_View->MouseEvent(mouseData, nullptr, nullptr);
Insert Keyframe rules
The CSSStyleSheet.insertRule()
method supports adding keyframe rules, but they won’t be indexed. Prysm will append keyframe rules at the very end of the stylesheet. The index, returned by the method will always be 0. Because deleting a rule requires an index, keyframe rules cannot be deleted at this point.
Backface visibility
The backface-visibility
property is evaluated per element. This differentiates from browser implementations where backface-visibility
applies to whole subtrees or contexts. If the developer wants to hide entire subtrees they can use backface-visibility: inherit
for the subtree of the parent element.