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

Content functions. #1582

Open
chriseppstein opened this issue Jan 5, 2015 · 40 comments
Open

Content functions. #1582

chriseppstein opened this issue Jan 5, 2015 · 40 comments
Labels

Comments

@chriseppstein
Copy link

@chriseppstein chriseppstein commented Jan 5, 2015

I'd like to introduce a function content() that returns a Sass data structure that represents the css specified as mixin content that is normally placed by the @content directive. The exact form of this data is something that would need to be well specified, I will work on that if people are in agreement that this is a good idea.

I also think Sass should provide a mixin that effectively translates this data back into CSS. E.g. @include expand-content(content()); would be identical to @content; when used inside a mixin. Sass doesn't currently expose any mixins automatically so we probably just want to make a special import location so that Sass mixins can be manually imported if they are needed. @import 'stdlib' or something?

Here's the rationale. I see a lot of users clamoring to use SassScript to manipulate their CSS. To do this, they end up defining their CSS as maps instead of as CSS. I'd like things that are stylesheets to be specified in CSS syntax, not in some it's a map and it's almost css syntax just so that it can be manipulated.

Another use case is that, https://github.com/oddbird/true needs a way to verify that the output of a mixin is correct without relying on string-based output comparison tests. By providing this capability, the css output of a mixin can be tested using SassScript.

In the past, I've proposed special directives to accomplish this, but I don't think that's necessary.

@chriseppstein chriseppstein added this to the 4.0 milestone Jan 5, 2015
@StefanoRausch
Copy link

@StefanoRausch StefanoRausch commented Jan 6, 2015

Indeed that would be great to have!

Regarding the testing of Sass / mixins output, there is currently a viable way via SassUnit. It works really well.

@jakob-e
Copy link

@jakob-e jakob-e commented Jan 8, 2015

👍 +1

@jakob-e
Copy link

@jakob-e jakob-e commented Jan 8, 2015

This may be a bit off topic but when talking content manipulation – how about using @content as a kind of getter-setter (if possible working like "map-merge" to reduce CSS output). I know this example has a lot of unresolved – like nested selector output, shorthands and fallbacks (font:1em serif; font-size:1rem; font-size: 16px;). It was not my intention to spam :-)

@mixin a(){
  left: 0;
  right: 100px;
}

@mixin b(){
  left: 100px;
  top: 100px;
}

@mixin c(){
  // Passed @content will be present before any modifications 

  // Set @content (merge)
  // Note! 
  // ; is a separator 
  // will require content to be "@at-root" (not inside selectors)
  @content( 
    @include a();
    @include b();
  );

  // Looking up property
  @if content(top) {
    // Merge properties 
    @content( bottom: 100px; ); 
    // Remove properties
    @content( width: null; height: null; ); 
  }

  // Print content 
  @content;
}


.class {
  @include c(){
    position: absolute;
    width: 100%;
    height: 100%;
  };
}


// CSS
.class {
  position: absolute;  // from .class
  // width : deleted;
  // height: deleted;
  left: 100px;   // from b (order from a)
  right: 100px;  // from a
  top: 100px;    // from b
  bottom: 100px; // from c
}
@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 8, 2015

In general, I like the idea of being able to do:

@mixin some-mixin() {
  $some-content: content();
  @content $some-content;
}

I think this could be optimized better than using a pure mixin and it's clear that it's based on existing patterns. As long as the variable passed to @content is properly structured, it could work with pure data that is assembled by hand -- it wouldn't have to come from the content() function.

Regarding the other suggestions here, I think you've missed just how complex the data that is passed as mixin content can be. It can contain selectors, media queries (and other css at-rules), etc. It needn't just be properties. In either respect, I think the fact that the content is returned as a SassScript data structure means that we can use the existing map, string, and list manipulation functions to operate on it.

@lolmaus
Copy link

@lolmaus lolmaus commented Jan 8, 2015

Does this suggestion also open a possibility of emitting arbitrary content via @content without prior capturing the content via content()?

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 8, 2015

@lolmaus yes. I don't see why it shouldn't.

@jakob-e
Copy link

@jakob-e jakob-e commented Jan 8, 2015

@chriseppstein I know – it was just a bit of crazy thinking :)

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 8, 2015

Crazy thinking is how you get good ideas. Also bad ones. The skill is in how to discern which is which.

@nex3 nex3 removed this from the 4.0 milestone Jan 9, 2015
@nex3
Copy link
Contributor

@nex3 nex3 commented Jan 9, 2015

I'm removing Milestone 4.0 because I don't want to block 4.0 on any major features other than the import overhaul.

This is a piece of functionality that would certainly solve a lot of use cases, but it risks introducing a colossal amount of complexity in the process. I'm on board with the general idea, but I want to be damn sure we have a nice, clean, comprehensible, and minimally-complex data format before we add it to the language.

Here's one example of a tricky principle we'll need to figure out: what state of resolution is the captured data structure in? In particular, how much nesting does it preserve? What happens when the user's code includes &? What about a deeply-nested &? What about @at-root? What about @if?

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 9, 2015

@nex3 I agree with your comments about the data format and look forward to discussing what we think that should look like. I have a few ideas that I can propose as a starting point for discussion but nothing I am wedded to.

Regarding the state of the captured data, the only thing that makes sense to me is that it is fully resolved CSS from the lexical scope of the include. At the point that this content is placed into the stylesheet again, they can use Sass constructs like & and @at-root to manipulate the new context of the content. Reproducing Sass code like you mention is exactly what mixins are good for and if we ever needed such a construct it would probably be some sort of lambda equivalent for mixins.

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 30, 2015

I recently sat down with @eoneill to review this design and make sure that it would support a better, more author friendly way of expressing a CSS component system like https://github.com/linkedin/archetype.

We identified a few more aspects of this feature that are needed to properly round out this concept and completely avoid the "data structures as alternative to CSS" issue.

The main issue with the proposal here is that it makes late-binding of some kinds of values more complicated. To fix this, my idea is that there should be a function that invokes a mixin in a given selector scope (defaulting to &) and returns the resulting CSS as a data structure like content() would. For this, I think a function like content-from-mixin($mixin-name, $selector-context: &, $arglist...) would suffice. This would allow static CSS and mixins to both work together to produce components. We should also make sure to implement #626 for dynamic mixin definitions and includes.

We also talked about how the css data would be structured.

CSS Fragment:

.foo, .bar {
  color: red;
  color: rgba(255, 0, 0, 0.5);
}
/* This is a comment about the media block that follows. */
@media (max-device-width: 400px) {
  /* A comment inside the media block. */
  aside#sidebar { width: 100%; }
}

As data:

$css-fragment: (
(ruleset: (selector: ((".foo",), (".bar",)),
           properties: (
             (color: red),
             (color: rgba(255, 0, 0, 0.5)),
           )),
(comment: " This is a comment about the media block that follows. "),
(at-rule: (name: "media",
           value: (max-device-width: 400px)
           contents: (
                       (comment: " A comment inside the media block. "),
                       (ruleset: (selector: (("aside#sidebar",),),
                                  properties: ((width: 100%),)))
                     )
          )))
);

For constructing this data structure, convenience functions can be provided:

$css-fragment: (
 ruleset(".foo, .bar", ((color: red), (color: rgba(255, 0, 0, 0.5)))),
 comment(" This is a comment about the media block that follows. "),
 at-rule("media", (max-device-width: 400px),
         comment(" A comment inside the media block. "),
         ruleset("aside#sidebar", (width: 100%)))
);

Manipulating this structure in SassScript is tedious at best due to the immutability of maps. I'm not sure what to do about that. Maybe provide some way of walking the "AST" by passing a function that can perform specific mutations leaving all the side-effect management to the caller?

@nex3
Copy link
Contributor

@nex3 nex3 commented Jan 30, 2015

Can you go into more detail about the late-binding issue and how content-from-mixin() fixes it?

Also, how are you thinking at-rule values will be parsed? I'd expect them all to be plain strings, but you seem to have the media query represented as a map there.

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Jan 30, 2015

So imagine you have a function current-locale() that let's you vary behavior based on what locale your css is targeting at that point in the stylesheet. If you check this function when a CSS fragment is captured (at definition time) then the value of current-locale() won't be correct. Mixins handle this problem very nicely, but the issue is that you then need to get the output of the mixin as data so that it can be merged with other more static structures. With dynamic mixin invocation, one could, with the help of some global functions, get access to the mixin's output as data, but this would be much more clunky than a function that just does it.

@mixin capture-mixin-output() {
  $last-captured-output: content() !global;
}
@mixin capture-mixin($mixin-name, $arglist...) {
  @include capture-mixin-output() { @include call($mixin-name, $arglist...); }
}

// ...

#some-context {
  @include capture-mixin(foo);
}
$foo-content: $last-captured-output;

And this approach would make it hard to access this mixin content from within pure functions since @include is disallowed with @function but since this operation is side-effect free (except for maybe affecting some global variables) there's no reason to make it so hard to use from within a function.

@nex3
Copy link
Contributor

@nex3 nex3 commented Feb 7, 2015

Can you give me an example of the use of content-from-mixin() with your current-locale() example?

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Feb 17, 2015

@nex3

$locale: en_US;
@function current-locale() {
  @return $locale;
}

@mixin with-locale($temp-locale) {
  $original-locale: $locale;
  $locale: $temp-locale !global;
  @content;
  $locale: $original-locale !global;
}

@mixin font-family() {
  @if current-locale() == "zh_CN" {
    font-family: "Microsoft JhengHei", sans-serif;
  }
  @else if current-locale() == "ar_AE" {
    // ...
  }
  @else {
    font-family: Helvetica, sans-serif;
  }
}

@mixin main-typography {
  p { @include font-family; }
}

@include register-component(main-typography);

// ...

@include component(main-typography);

[lang^="zh"] {
  @include with-locale(zh_CN) {
    @include component(main-typography);
  }
}

Obviously, in this simplified example there's no need for the component indirection, but you can imagine that the component system allows precision tweaks to registered components in different contexts or themes that makes it necessary to manipulate the evaluation time result of the mixin as data before outputting it.

@nex3
Copy link
Contributor

@nex3 nex3 commented Feb 20, 2015

I'm sorry, I'm still puzzled :p. Your example makes sense, but I don't see why content-from-mixin() is needed; if main-typography() is dynamically invoked when component() is called, won't it automatically see the correct dynamically-scoped locale without any extra help?

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Mar 3, 2015

@nex3, yes, but we need to intercept the results of running that mixin to merge it with other information in our theming/component system. We need the results of the mixin as data.

@eoneill
Copy link

@eoneill eoneill commented Mar 4, 2015

Here's a slightly more complex example that might demonstrate the idea @chriseppstein and I have tossed around...

// allows us to keep a store of component definitions
$component-store: () !default;
@mixin register-component($id, $def) {
  $component-store: map-merge($component-store, (
    #{$id}: $def
  )) !global;
}

// allows us to output the styles associated with a component definition (given a set of modifiers)
@mixin component($id, $modifiers: null) {
  $cmpt: map-get($component-store, $id);
  // IMPORTANT: we need to compute the definition styles given all the modifiers passed in
  // this will require us to manipulate the data before we output it
  $styles: get-component-styles($cmpt, $modifiers);
  @content $styles;
}

// given the component definition and the modifiers, merge the rules together (or some other significantly complex operation)
// note that this naturally feels like it'd be a function, and not a mixin
@function get-component-styles($cmpt, $modifiers) {
  $styles: content-from-mixin(map-get($cmpt, default));
  @each $modifier in $modifiers {
    // assume `merge-styles` does some complex operation
    $styles: merge-styles($styles, content-from-mixin(map-get($cmpt, $modifier)));
  }
  @return $styles;
}

// IMPORTANT: because we have dynamic values within this mixin, we have to invoke it each time, and can't compute the styles up-front
$button-color: black !default;
@mixin button {
  background: $button-color;
  color: invert($button-color);
  font-size: 100%;
  margin: 2px 5px;
}

@mixin button-small {
  font-size: 80%;
  margin: 1px 3px;
}

@include register-component(button, (
  default:  button,
  small:    button-small,
  // etc...
));

.btn {
  @include component(button);
  &.btn--small {
    @include component(button, small);
  }
  &.btn--large {
    @include component(button, large);
  }
  // etc
}

To be fair, the above example can be achieved purely using the capture-mixin-output mixin mentioned above, but it means we're now limited to only using the result within a mixin context. That is, we couldn't use get-component-styles as a function to do other data manipulation in another function call.

@nex3
Copy link
Contributor

@nex3 nex3 commented Mar 6, 2015

Ooooookay, I get it now. Yes, I agree that would be a useful function to have.

@helarqjsc
Copy link

@helarqjsc helarqjsc commented Nov 27, 2015

Are there any plans on implementing it or it was abandoned?
I've been trying to implement a mixin that will allow you to use media queries in any place and have them combined in the end of the resulting .CSS file. It works, but the syntax is not exactly pretty: https://github.com/helarqjsc/SASS-mixin-joined-media-queries/blob/master/example.scss
Being able to put @content into a variable would really help me here.

@chriseppstein
Copy link
Author

@chriseppstein chriseppstein commented Dec 3, 2015

@helarqjsc Things move slowly here in Sasslandia. We close issues when we decide not to do them. Right now, what we need is a design for how to represent the css abstract syntax tree as Sass values. That design needs to be very flexible, and also very user friendly.

Then what we need is an API that is efficient at mutating that AST -- all of the current Sass APIs really are quite bad at mutating deeply nested data structures. This API might be AST specific or it might just be optimizations for existing data types. It's not clear what the best way to handle this is. I can imagine a few different APIs and approaches to capturing the AST.

Then we can start writing code :) This is probably too big of a feature to make it into Sass 4.0 (a new module system is our top "big feature" priority right now) so it's hard to imagine this landing in the next 6 months.

@ArmorDarks
Copy link

@ArmorDarks ArmorDarks commented Feb 9, 2017

To be honest, CSS fragments from #1582 (comment) blowed my mind. In a bad way. () instead of {} and [] for maps and arrays notation didn't help it too...

Those days there are quite a lot of popular JS libraries (mostly around React), which trying to bring CSS to the object world, so maybe it would be good idea to check them and take some ideas from them.

Constructions like (ruleset: (selector: ((".foo",), (".bar",)), as very exessive and hardly friendly for endusers. Logical way to solve it would be to go Radium way and input selectors and derictives as you would normaly do in CSS or Jquery, like ".foo.bar" or "@media (...)". I understand that parsing those strings willl have performance impact, but can't help thinking that this seems to be the only legit way from consumers point of view.

After all, those objects-like data of Radium and other similar libs feels so natural, because they are very close to original CSS "objects". Well, in fact they are indeed objects, but with different syntax...

@ArmorDarks
Copy link

@ArmorDarks ArmorDarks commented Mar 2, 2017

Just for the information, I posted some related ideas in #2252

@jstoller
Copy link

@jstoller jstoller commented Jul 19, 2017

For what it's worth, I'd be happy to get @content as a string, as written, no compilation necessary. I'd like to do something like this:

@mixin ext() {
  $id: generate-placeholder-id(content());
  @include dynamic-extend($id) {
    @content;
  }
}

Where generate-placeholder-id(content()) generates a unique string based on the contents of @content. So, something like this:

.box1 {
  @include ext() {
    float: left;
    clear: left;
  }
}

.box2 {
  @include ext() {
    float: right;
    clear: right;
  }
}

.box3 {
  @include ext() {
    float: left;
    clear: left;
  }
}

is converted into this:

%ubh8jnee {
  float: left;
  clear: left;
}

.box1 {
  @extend ubh8jnee;
}

%abk4rtdt {
  float: right;
  clear: right;
}

.box2 {
  @extend abk4rtdt;
}

.box3 {
  @extend ubh8jnee;
}

To do this today I need to define my CSS as maps instead of as CSS, as @chriseppstein pointed out in the original issue, which is annoying to manage.

I have no idea what the implications of this would be, but my needs would be met by allowing #{@content} to be used as a function argument, like so...

@mixin ext() {
  $id: generate-placeholder-id(#{@content});
  @include dynamic-extend($id) {
    @content;
  }
}
@DonGissel
Copy link

@DonGissel DonGissel commented Aug 2, 2017

I would very much like to be able to extract the mixin-content as a string of sorts, and then insert it at a later time for "final parsing". My current use case is wanting to group my media queries together – I'm using a mixin for inserting media queries, like @include mq(sm) { color: red; } which works just fine, but if I do that a million times in my code, I'll end up with a million media queries. If my mq() mixin could store the content temporarily in a map indexed by the chosen breakpoint, append to that map whenever a similar media query is run, and then flush the whole thing at the very end of my "main" file, I would only have a handful of media queries, which potentially can save me quite a bit of bytes.

I know there are various plugins in NPM to achieve this particular scenario, but seen from my ignorant why-doesn't-SASS-contain-this-feature-standpoint, I see no reason why SASS should not support something like this. I do know that actually implementing it would be another thing entirely, but hey – a man can dream. ;-)

@ArmorDarks
Copy link

@ArmorDarks ArmorDarks commented Aug 4, 2017

@DonGissel good point, I was thinking about exactly same thing some time ago.

Btw, it needed not only to save few bytes. According to latests Google Lighthouse requirements, it is recommended to use media query or <link rel='stylesheet> to ensure, that certain breakpoints loaded only for certain browsers. In some cases it will drastically reduce size of stylesheets for specific devices.

As of right now, there is no way of doing that except using some PostCSS plugin to extract all media queries later into standalone files. From other side, may be it is intended way of doing things...

@cyraid

This comment was marked as spam.

@cyraid
Copy link

@cyraid cyraid commented Oct 13, 2018

Why was my comment marked as spam? I was only asking for an update. It's been 3 (almost 4) years since the original issue was created. There are people eagerly awaiting a response, or any update if we can be looking forward to this or if it's going to be rejected.

What are the blockers on this? Can we spark up the debate again instead of shoving it under the rug or is this just not that big of a priority? What's the plan?

@nex3
Copy link
Contributor

@nex3 nex3 commented Oct 15, 2018

@cyraid The appropriate way to indicate interest in an issue is to 👍 it. The appropriate way to hear about updates as they come is to subscribe. Posting comments like "+1" or "Any update?" just spams project maintainers and other users who are subscribed to the issue. The Sass team has limited resources, and not every issue is going to be addressed as quickly as you'd like.

@cyraid
Copy link

@cyraid cyraid commented Oct 15, 2018

How hard is it to say "still working on it guys" or "we haven't started on this because other issues are more important".. then maybe a voting system could be used to see what is more important.

Besides, it's been 4 years since the issue was created, and a year since any communication on the topic. It looks like abandonment to some, so 'bumping' it after that long for a status update I didn't think would be so terrible. Would someone really reply after a year after seeing a thumbs up? Don't think so.

@nex3
Copy link
Contributor

@nex3 nex3 commented Oct 15, 2018

How hard is it to say "still working on it guys" or "we haven't started on this because other issues are more important".. then maybe a voting system could be used to see what is more important.

Sass language design isn't a democracy. We do consider user demand (based on number of 👍s) when prioritizing issues, but we also consider many other factors. Again, we have very limited resources, and responding individually to every "Any update?" comment takes up those resources.

If someone is particularly interested in making a feature happen, they're encouraged to spend their own resources on helping to make that happen. But you don't get to insist that we allocate our resources on the features you want, or on responding to your comments in the way you want.

Besides, it's been 4 years since the issue was created, and a year since any communication on the topic. It looks like abandonment to some, so 'bumping' it after that long for a status update I didn't think would be so terrible. Would someone really reply after a year after seeing a thumbs up? Don't think so.

That's how most projects work. We use the issue tracker to track features we'd like to get to someday, which means that they can stay open with relatively little change for a long time.

@cyraid
Copy link

@cyraid cyraid commented Oct 15, 2018

Yes but, say I want to add the addition myself, and it does not conform to the team's design specifications, and I just wasted a ton of time because everyone would have wanted to discuss how it works first (usually how it goes in most open source projects). But if there are no resources to talk about it, then how am I to know what to implement?

@nex3
Copy link
Contributor

@nex3 nex3 commented Oct 16, 2018

If you'd put forth a proposal for discussion, I wouldn't have marked your comment as spam. But asking for an update without providing any new suggestion or volunteering to help contributes nothing to the discussion.

Arguing about this here also contributes nothing to the discussion. If you want to address this further, feel free to do it privately over email.

@cyraid
Copy link

@cyraid cyraid commented Oct 16, 2018

For sure, bringing forth a proposal I shall :) .. This entire issue almost entirely seems to be summed up with the ability to interact from within a mixin (as far as I'm aware). So taking the bits of the conversation (I hope I have got the most important bits), perhaps something like the below? Trading off usability complexity and implementation complexity, would satisfy most?

@mixin some-mixin() {

  // Yes this could be provided as a parameter, but other nested mixins may benefit from the content //
  @if (content-has(color) ) {
    color : content-get(color);
  } // IF //

  // Here, the test for the block content, and using it with no second parameter, no preceding block means actually including it //
  @if (content-has(some-block-content) ) {
    @content(some-block-content);
  } // IF //

} // Mixin //

.some-class {
  @include some-mixin() {

    // Having a second parameter here means setting a value //
    @content(color, black);

    // No second parameter, but having a block after means setting it as a block //
    @content(some-block-content) {
      color : red;
      background-color : black;
    } // Content //

  } // Include //
} // Style //

Thank you for taking the time to respond.

@nex3
Copy link
Contributor

@nex3 nex3 commented Oct 17, 2018

I don't want to tie the behavior too closely to @content in particular. If we're going to add all the complexity of being able to pull data out of a chunk of generated CSS, I want that CSS to be first-class: you should be able to assign it to a variable and pass it around like any other value.

I'm also not clear on what your proposal is doing. Look at the various proposals in the language repo for an idea of the level of detail we're looking for.

@cyraid
Copy link

@cyraid cyraid commented Oct 18, 2018

I see.. I had no idea there was a proposals area. This would have changed my mindset entirely and I would not have wanted an update here, seeing as most of the updates are happening there.. Question though, why didn't you just reference that to begin with? haha there's even a proposal there that is pretty much the same thing.

Edit: Regardless though, I'll see if I can think of anything to add to the content using proposal that will satisfy what would be very useful, and tend to the power users as well. I do see value in the content functions.

@Swoy
Copy link

@Swoy Swoy commented Sep 15, 2019

I apologize my potential ignorance, I could not find anything suggesting the following, so I wonder if this is doable, or even a good solution?

Say you have the following sass ( with @content ):

@mixin anchor-style() {
    @at-root {
      & {
        @content;
      }
      &:link,
      &:visited {
        @content;
      }
      &:hover,
      &:focus,
      &:active {
        @content;
      }
    }
}

If you then could do something like:

a {
    @include anchor-style {
        @content { // target all @content block.
            text-decoration: none; 
        }
        @nth-content(1n+2 to -n+3) { // target 2nd and 3rd content block.
            font-feature-settings: "frac" on, "c2sc" on;
        }
        @nth-content(3) { // target 3rd @content block.
            animation: pop-out-font 30ms ease;
            animation-play-state: running;
    }
}

it could make things a bit more organized IMHO. And maybe lessen the need for plenty mixins?

@nex3
Copy link
Contributor

@nex3 nex3 commented Sep 23, 2019

@Swoy That's a lot of complexity for a very narrow use-case. I think it would almost universally be clearer to just write out those styles more explicitly.

@iamkeir
Copy link

@iamkeir iamkeir commented Oct 25, 2019

Posting this to potentially help others with a slightly fugly work-around in the meantime that I have used with success and may help in some of use cases in this thread (and related threads).

Could use a !global variable declaration within your mixin and @content - crude example for generating responsive helper classes:

$breakpoints: (
  "": 0,
  "tablet": 700px
);

@mixin bp-classes($bp-list:$breakpoints) {
  @each $bp-class, $bp-width in $bp-list {
    $bp: $bp-class !global;
    @if $bp-width > 0 {
      @media (min-width: $bp-width) {
        @content;
      }
    } @else {
      @content;
    }
  }
}

@include bp-classes {
  .txt-align-left-#{$bp} { text-align: left; }
  .txt-align-center-#{$bp} { text-align: center; }
  .txt-align-right-#{$bp} { text-align: right; }
}

// Result
.txt-align-left { text-align: left; }
.txt-align-center { text-align: center; }
.txt-align-right { text-align: right; }

@media (min-width: 700px) { 
  .txt-align-left-tablet { text-align: left; }
  .txt-align-center-tablet { text-align: center; }
  .txt-align-right-tablet { text-align: right; } 
}

Can't take credit for this, it came from here: https://stackoverflow.com/questions/51473574/sass-pass-variable-to-content-from-within-a-mixin

Downside - you kinda have a vulnerable 'please do not touch me' global variable...

Also mentioned is the @content($var)/@include test-mixin() using ($var) approach but I was unable to get that to work. See https://stackoverflow.com/a/57582277/923785

Therefore, back to the original issue - I'm seeking to loop through and manipulate data in @content... but it feels murky/here be dragons.

@nolanwrightdev
Copy link

@nolanwrightdev nolanwrightdev commented Dec 17, 2019

Hello, I came here from #1289 which was closed in preference to this issue. My use case is to generate similar utility classes from other utility classes. For example, I might have the following css

.p4 { padding: 2rem; }

From that utility class, I might want to generate a number of other classes: ones that are identical to this class but apply only on certain breakpoints for example, or only in the hover state. This is akin to what TailwindCSS does to generate many, many utility classes, but I believe they use javascript to achieve this result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet