RE: Structuring CSS Stylesheets
Hi, > -Original Message- > From: Kevin Rushforth [mailto:kevin.rushfo...@oracle.com] > Sent: Monday, August 15, 2016 6:02 PM > To: David Grieve > Cc: Daniel Glöckner; openjfx-dev@openjdk.java.net > Subject: Re: Structuring CSS Stylesheets > > One slight correction on how to contribute below. > > > David Grieve wrote: > > > > > > On 8/15/16 10:52 AM, Daniel Glöckner wrote: > >>>> We found the culprits by patching the JRE, adding some statistics > >>>> to SimpleSelector and CompoundSelector. I was wondering whether > >>>> there are easier ways but anyway, it works ;) > >>> This sounds like some code that would be good to share with the > >>> community. :) > >> [DG] Sure thing. It's not too complicated and doesn't use external > >> libs. Any hint where I could post it / paste it? > > See https://wiki.openjdk.java.net/display/OpenJFX/Community for how to > > contribute > > That page is just a placeholder, and finding what you need in the sub-pages a > bit tricky. See the following page for how to contribute: > > http://openjdk.java.net/contribute/ > > -- Kevin > > > >> need them, for example our UI component factory would add table.css > >> to a TableView's list of stylesheets (tv. > >> getStylesheets().add("/path/to/table.css"). > >> The global theme.css would be minimal and only define colors and fonts. > >>>> What do you think about this approach? Will this work nicely with > >>>> caching of > >>> CSS styles in JavaFX? > >>> I think if you are going to go this route, you might want to use > >>> Region#getUserAgentStylesheets() which adds the styles as user-agent > >>> styles. > >>> But I don't think it will buy you much in terms of CSS performance. > >> [DG] We also want to control / override the CSS of standard JavaFX > >> controls like TreeTableView. Ideally we don't need to sub class them > >> so we would need to use parent. getStylesheets().add(), right? > > I doubt that getUserAgentStylesheets() or getStylesheets() is going to > > have much impact. My guess is that having the stylesheets added to the > > scene is going to be your best bet. I say this because the code that > > does the style matching has to combine styles together from > > Region#getUserAgentStylesheets() and Parent#getStylesheets(), whereas > > the styles from scene stylesheets are already combined. You have to > > think of these different sources of styles as sets of styles. When you > > have Region or Parent stylesheets, you have to create a union of those > > styles with the default user-agent stylesheets (e.g., caspian.css). > > With just scene stylesheets, you have just one set (this isn't 100% > > accurate, but close enough for this discussion). OK. So if we're talking about performance it might be a good idea to add the CSS to the scene and make sure that all CSS selectors are efficient. > > > >>> If you the biggest bang for your buck relative to JavaFX CSS > >>> performance, avoid style lookup and relative font sizes. > >> [DG] Could you explain what you mean by "avoid style lookups"? > > You know about styles like '-fx-base' used in caspian.css. You change > > the color for -fx-base and the basic colors of the UI change. This > > magic happens at runtime. So if I have a label in a cell in a table, > > and it has a style "-fx-border-color: -fx-base", JavaFX will - at > > runtime - try to resolve -fx-base into an actual color. It starts at > > the leaf and looks tries to resolve -fx-base. If it can't resolve it, > > it looks for a style in the parent node, and so on up the parent-chain > > all the way to the root node. The worst case scenario, then, is that > > there are no styles that resolve the value until you get to .root. > > > > This is what I mean by 'style lookups'. > > > > Its great stuff (the brainchild of Jasper Potts) because I can change > > the look of my UI just by setting '-fx-base'. But if I were developing > > a UI and I didn't care to let the users of my UI make such changes, > > I'd go through and remove all the lookups in caspian.css (not trivial > > because there are many many lookups - not just -fx-base). Or use a > > pre-processor such as SASS or LESS. > > > > The same sort of lookup happens when you have an em (or other relative > > size) because you need a font or a font-size to complete the > > calculation. In most cases, the lookup for a font or font-size goes > > all the way to .root, where it fails and falls back on > > Font.getDefault(). But its a trade off since em sizes let your UI more > > easily scale to different displays. > > Thanks a lot for the in-depth explanation. We're using a lot of style lookups in our CSS, mostly to define colors similar to -fx-base in your example. We will look at using a preprocessor as you suggested. This was anyway on our TODO list to be able to support user specific font sizes.
Re: Structuring CSS Stylesheets
One slight correction on how to contribute below. David Grieve wrote: On 8/15/16 10:52 AM, Daniel Glöckner wrote: We found the culprits by patching the JRE, adding some statistics to SimpleSelector and CompoundSelector. I was wondering whether there are easier ways but anyway, it works ;) This sounds like some code that would be good to share with the community. :) [DG] Sure thing. It's not too complicated and doesn't use external libs. Any hint where I could post it / paste it? See https://wiki.openjdk.java.net/display/OpenJFX/Community for how to contribute That page is just a placeholder, and finding what you need in the sub-pages a bit tricky. See the following page for how to contribute: http://openjdk.java.net/contribute/ -- Kevin need them, for example our UI component factory would add table.css to a TableView's list of stylesheets (tv. getStylesheets().add("/path/to/table.css"). The global theme.css would be minimal and only define colors and fonts. What do you think about this approach? Will this work nicely with caching of CSS styles in JavaFX? I think if you are going to go this route, you might want to use Region#getUserAgentStylesheets() which adds the styles as user-agent styles. But I don't think it will buy you much in terms of CSS performance. [DG] We also want to control / override the CSS of standard JavaFX controls like TreeTableView. Ideally we don't need to sub class them so we would need to use parent. getStylesheets().add(), right? I doubt that getUserAgentStylesheets() or getStylesheets() is going to have much impact. My guess is that having the stylesheets added to the scene is going to be your best bet. I say this because the code that does the style matching has to combine styles together from Region#getUserAgentStylesheets() and Parent#getStylesheets(), whereas the styles from scene stylesheets are already combined. You have to think of these different sources of styles as sets of styles. When you have Region or Parent stylesheets, you have to create a union of those styles with the default user-agent stylesheets (e.g., caspian.css). With just scene stylesheets, you have just one set (this isn't 100% accurate, but close enough for this discussion). If you the biggest bang for your buck relative to JavaFX CSS performance, avoid style lookup and relative font sizes. [DG] Could you explain what you mean by "avoid style lookups"? You know about styles like '-fx-base' used in caspian.css. You change the color for -fx-base and the basic colors of the UI change. This magic happens at runtime. So if I have a label in a cell in a table, and it has a style "-fx-border-color: -fx-base", JavaFX will - at runtime - try to resolve -fx-base into an actual color. It starts at the leaf and looks tries to resolve -fx-base. If it can't resolve it, it looks for a style in the parent node, and so on up the parent-chain all the way to the root node. The worst case scenario, then, is that there are no styles that resolve the value until you get to .root. This is what I mean by 'style lookups'. Its great stuff (the brainchild of Jasper Potts) because I can change the look of my UI just by setting '-fx-base'. But if I were developing a UI and I didn't care to let the users of my UI make such changes, I'd go through and remove all the lookups in caspian.css (not trivial because there are many many lookups - not just -fx-base). Or use a pre-processor such as SASS or LESS. The same sort of lookup happens when you have an em (or other relative size) because you need a font or a font-size to complete the calculation. In most cases, the lookup for a font or font-size goes all the way to .root, where it fails and falls back on Font.getDefault(). But its a trade off since em sizes let your UI more easily scale to different displays.
Re: Structuring CSS Stylesheets
On 8/15/16 10:52 AM, Daniel Glöckner wrote: We found the culprits by patching the JRE, adding some statistics to SimpleSelector and CompoundSelector. I was wondering whether there are easier ways but anyway, it works ;) This sounds like some code that would be good to share with the community. :) [DG] Sure thing. It's not too complicated and doesn't use external libs. Any hint where I could post it / paste it? See https://wiki.openjdk.java.net/display/OpenJFX/Community for how to contribute need them, for example our UI component factory would add table.css to a TableView's list of stylesheets (tv. getStylesheets().add("/path/to/table.css"). The global theme.css would be minimal and only define colors and fonts. What do you think about this approach? Will this work nicely with caching of CSS styles in JavaFX? I think if you are going to go this route, you might want to use Region#getUserAgentStylesheets() which adds the styles as user-agent styles. But I don't think it will buy you much in terms of CSS performance. [DG] We also want to control / override the CSS of standard JavaFX controls like TreeTableView. Ideally we don't need to sub class them so we would need to use parent. getStylesheets().add(), right? I doubt that getUserAgentStylesheets() or getStylesheets() is going to have much impact. My guess is that having the stylesheets added to the scene is going to be your best bet. I say this because the code that does the style matching has to combine styles together from Region#getUserAgentStylesheets() and Parent#getStylesheets(), whereas the styles from scene stylesheets are already combined. You have to think of these different sources of styles as sets of styles. When you have Region or Parent stylesheets, you have to create a union of those styles with the default user-agent stylesheets (e.g., caspian.css). With just scene stylesheets, you have just one set (this isn't 100% accurate, but close enough for this discussion). If you the biggest bang for your buck relative to JavaFX CSS performance, avoid style lookup and relative font sizes. [DG] Could you explain what you mean by "avoid style lookups"? You know about styles like '-fx-base' used in caspian.css. You change the color for -fx-base and the basic colors of the UI change. This magic happens at runtime. So if I have a label in a cell in a table, and it has a style "-fx-border-color: -fx-base", JavaFX will - at runtime - try to resolve -fx-base into an actual color. It starts at the leaf and looks tries to resolve -fx-base. If it can't resolve it, it looks for a style in the parent node, and so on up the parent-chain all the way to the root node. The worst case scenario, then, is that there are no styles that resolve the value until you get to .root. This is what I mean by 'style lookups'. Its great stuff (the brainchild of Jasper Potts) because I can change the look of my UI just by setting '-fx-base'. But if I were developing a UI and I didn't care to let the users of my UI make such changes, I'd go through and remove all the lookups in caspian.css (not trivial because there are many many lookups - not just -fx-base). Or use a pre-processor such as SASS or LESS. The same sort of lookup happens when you have an em (or other relative size) because you need a font or a font-size to complete the calculation. In most cases, the lookup for a font or font-size goes all the way to .root, where it fails and falls back on Font.getDefault(). But its a trade off since em sizes let your UI more easily scale to different displays.
RE: Structuring CSS Stylesheets
Hi, Thanks a lot for your comments, David. > -Original Message- > From: openjfx-dev [mailto:openjfx-dev-boun...@openjdk.java.net] On Behalf > Of David Grieve > Sent: Monday, August 15, 2016 4:35 PM > To: openjfx-dev@openjdk.java.net > Subject: Re: Structuring CSS Stylesheets > > > > On 8/15/16 9:46 AM, Daniel Glöckner wrote: > > Hi, > > > > We recently came across a number of performance issues which were caused > by our poor CSS. > > > > Our stylesheet contained too many selectors, specifically too many generic > selectors targeting "common" JavaFX controls (.text, .label etc.). > Make the selectors as specific as possible. Avoid the universal selector '*' > if you > can. > > > > We found the culprits by patching the JRE, adding some statistics to > > SimpleSelector and CompoundSelector. I was wondering whether there are > > easier ways but anyway, it works ;) > This sounds like some code that would be good to share with the community. :) [DG] Sure thing. It's not too complicated and doesn't use external libs. Any hint where I could post it / paste it? > > > > We've meanwhile improved our CSS performance (by making a bunch of > selectors more specific) but want to re-structure the stylesheets to be more > future-proof (with even better performance ;)). > > > > Could you quickly comment on the following idea? > > > > Our CSS is already divided into several stylesheets (e.g. table.css, some- > dialog.css etc.). > > These stylesheets are all imported via @import into a global theme.css. > theme.css is then added to the scene. > > > > We're thinking about adding the individual stylesheets only to nodes which > need them, for example our UI component factory would add table.css to a > TableView's list of stylesheets (tv. > getStylesheets().add("/path/to/table.css"). > The global theme.css would be minimal and only define colors and fonts. > > > > What do you think about this approach? Will this work nicely with caching of > CSS styles in JavaFX? > I think if you are going to go this route, you might want to use > Region#getUserAgentStylesheets() which adds the styles as user-agent styles. > But I don't think it will buy you much in terms of CSS performance. [DG] We also want to control / override the CSS of standard JavaFX controls like TreeTableView. Ideally we don't need to sub class them so we would need to use parent. getStylesheets().add(), right? > > If you the biggest bang for your buck relative to JavaFX CSS performance, > avoid > style lookup and relative font sizes. [DG] Could you explain what you mean by "avoid style lookups"?
Re: Structuring CSS Stylesheets
On 8/15/16 9:46 AM, Daniel Glöckner wrote: Hi, We recently came across a number of performance issues which were caused by our poor CSS. Our stylesheet contained too many selectors, specifically too many generic selectors targeting "common" JavaFX controls (.text, .label etc.). Make the selectors as specific as possible. Avoid the universal selector '*' if you can. We found the culprits by patching the JRE, adding some statistics to SimpleSelector and CompoundSelector. I was wondering whether there are easier ways but anyway, it works ;) This sounds like some code that would be good to share with the community. :) We've meanwhile improved our CSS performance (by making a bunch of selectors more specific) but want to re-structure the stylesheets to be more future-proof (with even better performance ;)). Could you quickly comment on the following idea? Our CSS is already divided into several stylesheets (e.g. table.css, some-dialog.css etc.). These stylesheets are all imported via @import into a global theme.css. theme.css is then added to the scene. We're thinking about adding the individual stylesheets only to nodes which need them, for example our UI component factory would add table.css to a TableView's list of stylesheets (tv. getStylesheets().add("/path/to/table.css"). The global theme.css would be minimal and only define colors and fonts. What do you think about this approach? Will this work nicely with caching of CSS styles in JavaFX? I think if you are going to go this route, you might want to use Region#getUserAgentStylesheets() which adds the styles as user-agent styles. But I don't think it will buy you much in terms of CSS performance. If you the biggest bang for your buck relative to JavaFX CSS performance, avoid style lookup and relative font sizes. Kind regards, Daniel
Structuring CSS Stylesheets
Hi, We recently came across a number of performance issues which were caused by our poor CSS. Our stylesheet contained too many selectors, specifically too many generic selectors targeting "common" JavaFX controls (.text, .label etc.). We found the culprits by patching the JRE, adding some statistics to SimpleSelector and CompoundSelector. I was wondering whether there are easier ways but anyway, it works ;) We've meanwhile improved our CSS performance (by making a bunch of selectors more specific) but want to re-structure the stylesheets to be more future-proof (with even better performance ;)). Could you quickly comment on the following idea? Our CSS is already divided into several stylesheets (e.g. table.css, some-dialog.css etc.). These stylesheets are all imported via @import into a global theme.css. theme.css is then added to the scene. We're thinking about adding the individual stylesheets only to nodes which need them, for example our UI component factory would add table.css to a TableView's list of stylesheets (tv. getStylesheets().add("/path/to/table.css"). The global theme.css would be minimal and only define colors and fonts. What do you think about this approach? Will this work nicely with caching of CSS styles in JavaFX? Kind regards, Daniel