-
Notifications
You must be signed in to change notification settings - Fork 113
Server-side: Media queries and pseudo classes for inline styles #8
Comments
For media queries, I would suggest to just read window dimensions in JS and re-render the entire page. For pseudo-class like :hover, my thought is to do hoverStyle={...}. This way if your component also implements hover in pure JS, it can use the same API. For :before and :after, just insert a new element in the DOM. Do you see anything else I missed? |
It would be nice to be able to do actual media queries so that server-rendered pages can be laid out correctly.
|
window.matchMedia would work well here |
I am having problems with the :focus pseudo classes. |
@spicyj Would the intention be that server-rendered pages would display correctly sans-JS? |
@ainscore Yes, that's what I meant. |
That sounds interesting, I've thought previously about a method where the styles are written into a style tag for server side rendering and parsed by code on the client similar to how the DOM is with current server-side rendering. This would leverage the css engine even for js-enabled browsers, but I don't know what kind of performance impact there would be from reading out the styles client side. And for inaccessible styles rules like :visited, the client side code could also write into a style tag. |
To solve media queries I ended up doing this https://github.com/wearefractal/react-responsive which I think makes way more sense |
@contra i like that solution for media queries applied client side, I was thinking more toward spicyj's point for sites that use react exclusively on the server side. And I think a large part of the reasoning behind the server-side rendering of react in general is that you get the initial static content pop, which may require media queries. |
@ainscore Server-side media queries could specify a default that is executed, or possibly parse user agents to guess the device specs and do your own matching. I'm planning on playing around with those ideas soon |
The "specifying a default" approach is the one I took with react-mediaswitch. The UA stuff is separate IMO, though it could be used to decide which media case is the default. We're also considering sending a separate XHR request for the initial view which passes along device dimensions (or a string that indicates which of the server-defined device dimensions is appropriate). |
Another take on react & media-queries : https://github.com/Cethy/react-mixin-media-query I used a " The nice side-effects I wanted to attain were :
Feel free to try it and send me some feedback. :) |
I clarified in the title, that this issue is concerned with server-side rendering. |
What do you think about having media information become a new object that updates a view (similar to this.state and this.props)? render: function(){
if (this.media.screenWidth >= 480) {
// desktop stuff
} else {
// mobile stuff
}
} |
@contra You can already do this via |
@sebmarkbage I fail to see why side is important here, server-side you could have default value or parameter passed from the client ; Am I missing something ? @contra That's pretty much what I'm trying to accomplish with my mixin. |
A "default" value, or event a guess from the user-agent, will sometimes be wrong. |
@parshap And how would you fix that ? "Isomorphically", you need to be able to handle media-queries the same way on both side. So you need a fallback value for when you don't have "screen size". |
@Cethy The mixin seems too complicated. I think something as simple as re-render on |
@Cethy: There are two separate things being discussed here:
These two things are different and have non-interchangeable behaviors. Your mixin is a way of doing (1). This issue is about finding a solution for (2). |
@contra you've got a point, I'll try to split my work to have something more simple. @parshap Thx for the clarification, i hadn't read the inline styles proposal (since the link from spicyj is broken, aha) ; now I understand, so forget my last intervention :) |
Updated the original link so that it works again. |
Perhaps it's a stupid proposition but with that kind of thing : https://gist.github.com/fdecampredon/86ccbba3863bccaec7dd |
If we're sticking to a very strict application of server-side rendering in which no javascript needs to run in order for the media queries and pseudo-classes to work correctly, I see two approaches. One would require compiling a stylesheet from the Javascript logic and sending that down with the html. The dom and stylesheet would then be parsed by React on the client side and any further application of styles would happen on the DOM. This would not necessarily render the exact same DOM tree on the server side as the client side(in this example, both bigContent and smallContent would be rendered on the server side and only one displayed on the client, whereas on the client side only one would be inserted in the DOM), thus it could result in rendering an unnecessary amount of HTML. However, the extra content would be removed after a render pass on the client side, so functionally this shouldn't be an issue(at least in a pure react environment). I'm not entirely sure if the javascript logic can be parsed into correct media queries in all cases but this code is how I imagine it happening in a simple case. (Showing examples for media queries but pseudo classes could be applied in a similar way) render: function(){
if (screen.width >= 480) {
// desktop stuff
return React.DOM.div({}, bigContent);
} else {
// mobile stuff
return React.DOM.div({}, smallContent);
}
} Rendered html: <div class="disp_0" >
<!-- big content -->
</div>
<div class="disp_1" >
<!-- small content -->
</div> Rendered stylesheet: @media (min-width: 480px) {
.disp_1 {
display:none;
}
}
@media (max-width: 479px) {
.disp_0 {
display:none;
}
} A second, simpler approach would allow specifying the media queries in React StyleSheet objects, so that only those objects would need to be processed by the stylesheet compiler. render: function(){
return React.DOM.div({},
bigContent({
style:StyleSheet.create({
base: {
//set prop as "none" if width < 480
display: React.Media.maxWidth(480)("none")
width: 1024,
height:40
}
})
}),
smallContent({
style:{
base: {
display: React.Media.minWidth(480)("none")
width: 480,
height:40
}
}
})
);
} Rendered html: <div class="disp_0" >
<!-- big content -->
</div>
<div class="disp_1" >
<!-- small content -->
</div> Rendered css: @media (min-width: 480px) {
.disp_1 {
display:none;
}
}
@media (max-width: 479px) {
.disp_0 {
display:none;
}
}
.disp_0 {
width:1024px;
height:40px;
}
.disp_1 {
width:480px;
height:40px;
} |
+1 for a simple way to apply inline pseudo styles |
var styles = StyleSheet.create({
styleName: {
'@media': React.Media.minWidth(700).andHandheld().andOrientation('landscape').style({
fontSize: 20
}),
':active': {
textDecoration: 'underline'
}
}
}); var options = {renderHidden: false, renderStyles: true, screen: { width: 480 }};
var { markup, css } = React.renderToString(<App />, options); |
Thinking about this problem I describe my solution in the following blog post, which introduces a new abstraction called VirtualCSS which is similar to CSS like VirtualDOM is to the DOM in react terms: https://medium.com/@jviereck/modularise-css-the-react-way-1e817b317b04 |
https://github.com/reactjs/react-future/blob/f8808dd4cd275dcc2a81b41989a71cd23ad98308/04%20-%20Layout/04%20-%20Inline%20Styles.md provides a proposed API for defining inline styles on a component. In some cases, it's necessary to use media queries or pseudo classes in a selector, which isn't directly possible with inline styles. Any ideas here?
cc @vjeux
The text was updated successfully, but these errors were encountered: