Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse classNames to inline styles. #96

Closed
smeijer opened this issue Jan 24, 2021 · 14 comments
Closed

Parse classNames to inline styles. #96

smeijer opened this issue Jan 24, 2021 · 14 comments
Labels
pr³ ✨ Feature New Feature ❓ Question Further information is requested

Comments

@smeijer
Copy link
Collaborator

smeijer commented Jan 24, 2021

It would be nice if we could use the server side rendering part, to style emails with this library.

The thing is, not all mail clients know how to handle style tags. The recommended approach is still to use inline styles (<div style="color: red">).

I do realize that it's not possible to support everything with that approach, but even partial support could be of immense value when creating mail templates.

Things that are unsupported (like media queries) could still go to the head style sheet for those clients that do support it.

It would also mean that css variables should be resolved.

Thoughts?

@sastan
Copy link
Collaborator

sastan commented Jan 24, 2021

For the apply function we have added context.css (https://twind.dev/api/interfaces/twind.context.html#css) which extracts all CSS rules. Something like this may work:

let rules
tw(({ css }) => {
  rules = css('text-center')
  /// rules = css([apply`...`, 'text-center text-xl', css`...`])
  return ''
})
// => rules = { textAlign: center }

Then we need to convert the object to styles (hyphenate, and some other stuff). The functionality is already internally available.

Maybe we could define a new module (twind/style) to do that.

@sastan sastan added pr³ ✨ Feature New Feature ❓ Question Further information is requested labels Jan 24, 2021
@sastan
Copy link
Collaborator

sastan commented Jan 26, 2021

With #101 in place we could expose the css context as tw.style or tw.css.

tw.style`text(center white) bg-black`
// => { align: "center", color: "#fff", ...}

@tw-in-js/contributors Thoughts?

@just214
Copy link
Collaborator

just214 commented Jan 26, 2021

I don't know enough about this problem/ use case, but that seems really nice for those who might need it. I might lean towards style simply because that is most likely the attribute that you would apply it. I would expect css would generate valid CSS syntax.

I wonder if it is possible, or useful, to optionally generate the styles in raw format: text-align:center; color: #fff;?

@smeijer
Copy link
Collaborator Author

smeijer commented Jan 26, 2021

The raw variant is the idea behind this issue.

I was thinking to use twind for styling email templates, but than I'd need to end up with inline styles, in string format.

<div style="text-align: center; color: #fff;">
  hi
</div>

@just214
Copy link
Collaborator

just214 commented Jan 26, 2021

That’s kind of what I figured. The style function proposed by @sastan seems like a nice, easy way to get a limited version of Twind via inline styles. I can’t imagine it could get much easier than this:

<p id="title">
  Hello, friend.
</p>

<script type="module">
  import { tw } from 'https://cdn.skypack.dev/twind';
  
  const el = document.getElementById("title");
  el.style = tw.style`text(blue-500 uppercase) p-2`;
</script>

I’m sure there are a plenty of considerations and challenges that I haven’t thought of but it seems like a neat idea.

@sastan
Copy link
Collaborator

sastan commented Jan 27, 2021

@smeijer Do you want to use this feature for https://github.com/rakered/rakered/tree/main/packages/email?

I agree that tw.style should return an CSS Style object. That means only properties.

What do we do about child selectors, pseudo classes, global styles? The only reasonable approach I see is to throw an error because we can not add a class or something like that.

@smeijer
Copy link
Collaborator Author

smeijer commented Jan 27, 2021

That was the idea indeed. That way I could clean up this mess: https://github.com/rakered/rakered/blob/main/packages/email/src/templates/themes/default.ts 😬.

Some things would indeed not be possible, that's why I mentioned:

Things that are unsupported (like media queries) could still go to the head style sheet for those clients that do support it.

IF this is something that you'd want to support, the inline style support would be very basic. Some things won't be supported, or would still end up in the head > style. Think media queries, but indeed also pseudo-classes and child selectors.

So I think that's a decision that should be made first. Not everything can end up in the style=<string> tag, so does this match the product? Is it worth it to create a twind/email package for it? (email styling is associated with basic and shitty css), or should we just really not want to go that way? (Totally understand if that's the case!)

@sastan
Copy link
Collaborator

sastan commented Jan 27, 2021

After thinking about tw.style I do not really see a use case for it that warrants it be included in the twind module. It has so many implications and things that can not work. Is there a case where style would be preferred over class?

A separate module like twind/email may be the way to go.

After looking at Email Client CSS Support head > style, except for Gmail App, seems to have good support.

@smeijer Wouldn't the getStyleTag (optional with shim) be enough? What am I missing?

@mattrossman
Copy link

I found a similar issue discussed on the styled-components repo, which pointed to tools like inline-stylesheet or inline-css for solving this. It looks like for the latter, it would be straightforward to convert a document rendered with getStyleTag into inline style strings.

@smeijer
Copy link
Collaborator Author

smeijer commented Jan 27, 2021

except for Gmail App, seems to have good support.

Unfortunately, that's a big one 😞

Yes, the getStyleTag would definitely be useful! I'm working on an edge case here, so don't spend too much time on it!

What would it look like when using it together with the shim?

@sastan
Copy link
Collaborator

sastan commented Jan 27, 2021

@mattrossman That makes things easier for us.

Something like the following should work already:

  1. uses twind SSR to render the app (optional with shim)
  2. uses the inline-css package to adjust the html
  3. Profit

Based on a react app:

import { renderToString } from 'react-dom/server'
import inlineCss from 'inline-css'

import { setup } from 'twind'
import { virtualSheet, getStyleTag } from 'twind/sheets'

import App from './app'

const sheet = virtualSheet()

setup({ ...sharedOptions, sheet })

function ssr() {
  // 1. Reset the sheet for a new rendering
  sheet.reset()

  // 2. Render the app
  const body = renderToString(<App />)

  // 3. Create the style tag with all generated CSS rules
  const styleTag = getStyleTag(sheet)

  // 4. Generate the html
  const html = `<!DOCTYPE html>
    <html lang="en">
      <head>${styleTag}</head>
      <body>${body}</body>
    </html>
  `

  // 5. Inline the CSS – returns a Promise
  return inlineCss(html, { /* options */ })
}

If this works it is an extension to the existing SSR examples (incl the shim) as only the last line is specific to email. We could add a recipe or ad it to the FAQs.

@sastan
Copy link
Collaborator

sastan commented Feb 1, 2021

@smeijer Does the example work as you want it? Then I would add a section to the docs and close this one.

@smeijer
Copy link
Collaborator Author

smeijer commented Feb 1, 2021

@sastan, I just tried it, and the output is sufficient for my needs! Thanks.

Just good to know, the non-supported classes don't seem to end up in head > style.

https://runkit.com/smeijer/twind-inline-styles

@sastan
Copy link
Collaborator

sastan commented Feb 20, 2021

Documentation will be added via #125

@sastan sastan closed this as completed Feb 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr³ ✨ Feature New Feature ❓ Question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants