We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Dynamically Sassy

00:00

Formal Metadata

Title
Dynamically Sassy
Title of Series
Part Number
51
Number of Parts
94
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
When we want to offer customizability to the users of our applications, things can get tricky. How do we allow users to customize the look of the user interface while reusing the static CSS we’ve already designed? There is a way, but it is fraught with many dangers. Learn about the power of dynamically generating CSS from Sass files. Tackle the foes of dynamic content injection, rendering, caching, and background processing. In the end, we will look triumphantly at our ability to reuse our application styles to create customizable interfaces for our end users.
Multiplication signComputer animation
outputSoftware as a serviceSuite (music)ACIDComputer animation
Cache (computing)outputFunctional (mathematics)Content (media)Context awarenessProcess (computing)WordIdentifiabilityCloud computingSoftware as a serviceComputer animation
TwitterWeb-DesignerRemote procedure callDebuggerComputer animation
Product (business)Software as a serviceAttribute grammarWebsiteTask (computing)BuildingContent (media)Drop (liquid)Drag (physics)Different (Kate Ryan album)User interfaceClient (computing)Block (periodic table)Text editor
Different (Kate Ryan album)Electric generatorGraph coloringImplementationQuicksortWebsiteVideo gameState of matterMultiplication signComputer animation
ImplementationGraph coloringCodeContext awarenessProduct (business)Complex (psychology)Default (computer science)Fluid staticsRule of inferenceComputer animation
Process (computing)PreprocessorComputer animation
GUI widgetData structureDifferent (Kate Ryan album)ProgrammschleifeSocial classLevel (video gaming)Rule of inferenceLoop (music)Computer fontGraph coloringVariable (mathematics)CASE <Informatik>Set (mathematics)NamespaceInclusion mapModule (mathematics)Web 2.0Computer fileMarkup languageWeb pageModul <Datentyp>Functional (mathematics)MathematicsSoftware testingFormal languagePosition operatorMedical imagingCloud computingComputer animation
CASE <Informatik>Computer fileGraph coloringVariable (mathematics)Cellular automatonGroup actionContext awarenessMetropolitan area networkComputer architectureComputer animation
Interior (topology)Context awarenessElectronic mailing listElement (mathematics)Graph coloringComputer fileFunctional (mathematics)SpacetimeSet (mathematics)Variable (mathematics)Message passingMultiplication signNumberData structureSubject indexingCloud computingFluid staticsComputer animationLecture/Conference
Functional (mathematics)Context awarenessFormal languageType theoryExtension (kinesiology)Content (media)Dynamical systemString (computer science)Multiplication signScripting languageGraph coloringParameter (computer programming)Electronic mailing listSpacetimeSocial classHexagonLevel (video gaming)Module (mathematics)Cloud computingSet (mathematics)Symbol tableLimit (category theory)Pointer (computer programming)MappingCompilerNumberMaxima and minimaEndliche ModelltheorieComputer animationLecture/Conference
Client (computing)Dynamical systemComputer animation
Fluid staticsQuicksortContext awarenessTemplate (C++)Dynamical systemMobile appCloud computingComputer animation
Product (business)Social classDynamical systemVolumenvisualisierungContent (media)QuicksortComputer animation
Template (C++)Key (cryptography)String (computer science)Social classComputer configurationComputer fileDivisorGraph coloringLogical constantNumberContext awarenessVariable (mathematics)QuicksortFunctional (mathematics)Type theoryInstance (computer science)Execution unitMessage passingVolumenvisualisierungElectronic mailing listGame controllerArtistic renderingFile systemScripting languageCloud computingMultiplication signMathematicsGreatest elementSymbol tableHash functionLinear multistep methodComputer animation
Computer fileFormal languageCloud computingError messageVolumenvisualisierungComputer animation
Structural loadFluid staticsComputer configurationInclusion mapMessage passingComputer fileCASE <Informatik>Directory serviceComputer animationLecture/Conference
Set (mathematics)Demo (music)Level (video gaming)Graph coloringMobile appVolumenvisualisierungComputer animation
Transcript: English(auto-generated)
Good afternoon, everyone. How are we doing after lunch? Feeling all right? Sweet.
Thank you for coming out to this. Don't normally see a lot of talks on SaaS, so I hope you'll find this one interesting, because we're going to look at making it a little more dynamic. And just to give you kind of a preview, so really what we're wanting to accomplish is take our SaaS
stylesheets and in a dynamic way take in user input from the client and be able to render out dynamic CSS so it's not so static like the stylesheets we might use in the asset pipeline. So what are we going to talk about then? Obviously, we're going to generate dynamic CSS.
That's the topic for today. And like I mentioned, this is going to be based on user input. So we're going to learn about writing SaaS functions in Ruby actually, because we're going to have to figure out some way to get some dynamic content into a stylesheet context. And along the way, we'll find that this may not be
the most performant route, so we're going to identify performance issues and think of ways that we can resolve and fix that. So that means we are probably going to look at caching and even maybe some background processing. Before we get too far, I'm Jeremy. I live in Tennessee in a very small town.
Or I'm lpapapoyo on Twitter. I work for a company called Push Agency. We are a completely distributed team, so I'm a remote web developer. I do a lot of Rails and JavaScript. So I'm back end guy, front end guy, full stack, whatever you want to call it.
So we do a lot of client work, but we have this product called Simply Build. And Simply Build is a website builder, editor, and you can have as many websites as you want. You can edit your sites directly looking at them. So we have a drag and drop interface for different blocks of content. And you can rearrange those blocks and edit them directly
via the content editable attribute that's available in HTML5. So why am I bringing up Simply Build, though? We're here about SaaS. Am I just going to pitch our product to you? Well, maybe. I think it's pretty awesome. But this is related to the talk.
So earlier in this year, I was working on a task for Simply Build, a new feature. So at the time, Simply Build, for your website, you could select from a few themes. And then within each theme, you could select your color palette. And that would determine what navigation colors you're using,
what background colors are being used, text color, et cetera. But we wanted to offer that in a custom manner, to where a user wouldn't be stuck with just whatever palettes we have. And they could customize it. And we wanted the user experience to be pretty nice. So we didn't want to just have a color wheel, and you select all your swatches.
And more than likely, you're going to get frustrated. It's not going to look good, and you're going to hate us. So we thought, let's let them pick a color, sort of a seed color. And then we'll generate palettes based on some different color harmonies. And then that way, we can let them customize it, but still generate something that's going to look
good for their website. So this was the problem that I was tasked with solving. And so there were some implementation issues that I had to start to consider. First thing, we already have these style sheets, and we're using them in a static context. So we have all these complex rules in SAS that determine
what background color gets used, for which palette, text color, et cetera. Well, it doesn't make sense to re-implement all this and duplicate code just for a dynamic context. So we want to put this in a manner where I can reuse the style sheet in both our static default context and in the custom color context.
And that means we're probably not going to use the asset pipeline, especially not if we're in production. So we're going to have to somehow get this to work from a controller and render out that way. But we'll find that SAS isn't very quick at rendering, especially when you get pretty complex style sheets.
So we'll look at caching generated CSS and maybe even rendering in the worker. And so these were some of the research I did in looking into getting this to work with Simply Bill and some of the implementation issues that I ended up facing.
So just as a quick introduction, I'm sure most of you have already used SAS and Rails, but just to let you get a feel for it if you've never seen it before. If you're new to SAS and Rails, it's syntactically awesome style sheets. And SAS is a CSS preprocessor. So it offers you some different syntax that looks like CSS,
but ideally is going to make your job easier to write your CSS in a more manageable, maintainable way. And here's just a basic overview of what some SAS looks like. So we have variables. The nice thing about variables is if you have a certain font size or text color you like to use in your style sheets, instead of constantly duplicating that
over and over, we'll set it to a variable. And then we can use our variable throughout our styles. And if we need to make a change, all we have to do is change the value of our variable. We also have nested rules. So with nested rules, it allows you to avoid the whole descender selectors, descendant selectors that can be
super long, and this way you can kind of namespace your SAS rules. We can include other SAS style sheets via the import keyword, and that allows us to make our files more modular. We can devote this style sheet over here to some widget, and this one to this web page, et cetera.
Mixins, they're kind of like modules in Ruby. I can create some rules that I know I will want to use in more than one class or selector, and I can just include them, and that helps avoid that sometimes you want to extract out some common class, and then you've got to add more classes to your markup.
So this helps you kind of avoid that. So what? I know there's debate sometimes whether CSS preprocessed or needed or not. I really like it. Obviously it gives you modularity. I can separate out different widgets and pages, and I can import them as needed, and it helps me keep my style
sheets more maintainable and clean. Obviously with mixins and variables, it helps enforce the drive principle. We also actually have data structures and scripting in SAS. So it's a language, and you can capitalize that and use loops and whatnot to also help reduce repetitiveness in
your CSS. Like a great example is a background sprite image, and you want to set where the positioning is. So you could create a map which has the class you want to use for a position, the actual background position, and then loop over that and generate your rules that way. And there's also color functions, which is really
helpful, especially in this case with custom colors where I can take a color, lighten it, darken it, and then use that modified color in some way. And that's SAS. All right, so let's get on to what we're really going to talk about today. So first thing is we want to reuse these style sheets.
And we'll find out it's in the variables. So we want to architect our files in a way that we have some global variable that has, in this case we'll see, our palette of colors. And we'll import another file, which is actually the style sheet we're going to reuse. And so that imported file is going to depend on some
global variable that needs to exist. And it's going to be able to use that then in generating these styles. So let's look at the static context first. So I have three SAS files here. The top one, that's going to be our simplified UI SAS file. So we have this foo selector, we have a
background, and a color. Now notice we're calling this int function. So SAS has lists. I mentioned they have data structures. This palette variable is going to be a list. So like you might guess, if I call int on a list and pass in a number, I'm going to grab that int element from
the list. And you'll also notice it starts at one. So SAS lists are just indexed starting at one instead of zero. So we go down to the next two files. We have a Palette1 as CSS and a Palette2 as CSS. And you'll notice I'm setting a list there.
The first one, the palette. And I just use space delimiter, wrap it in parens just to make it more explicit what I'm doing. You can use commas too for lists. And it's going to be consisting of red and green. And then I import my UI file. Below that, I have the second palette. And I'm setting again a palette list, but this time
it's blue and yellow. And I'm importing the UI. So basically what that's going to do, I've set this global scope, palette is defined. And when I import this file, it's going to see that global variable, and it's going to use that. So already you can see how we can reuse these style sheets in the static context. But we want to start looking at dynamic context.
And this is where we're going to look at SAS functions. So here we have another style sheet. This time I'm setting palette equal to the return type of this get dynamic palette function. And again, I'm importing my UI. So where does get dynamic palette come from?
So SAS has this module, SAS script functions. And any method you add to that module will make that method available as a function in your SAS style sheets. And if you've ever programmed in a host language where you're defining some function for the target language, you'll know you have to work in types that are
available in the host language. So if you've written a C extension for Ruby before, you know your C function, it's not going to return an integer, it's not going to return a character pointer, it's going to return a Ruby value type. So the same idea applies here with Ruby and SAS.
So walking through this function here, we're going to create a palette again. I'm calling two times map, so it's going to be two colors. I'm just generating two random hexadecimal strings. And then I'm calling this function on this very long module, SAS script value color. So underneath SAS script value exists all these types
in SAS. There's colors, numbers, lists, et cetera. So color has this convenient class level method called from hex. And obviously, like you might guess, it'll take a hexadecimal string, and it'll return this color value type. So I'm going to basically create an array of two colors,
SAS colors. And there at the bottom, I'm going to pass that into a SAS script value list. So it expects, when I instantiate it, it expects an array of SAS value types. And then the other parameter there, which is the space symbol, is basically saying this is the delimiter I want
to use in my list. OK, so that's pretty cool. We can get some type of dynamic content from Ruby into SAS, but what about injecting data from a user? Because we want this to work somehow in the Rails ecosystem, where the client makes a request, and we get back some dynamic CSS to them.
So I'm basically saying here, I want getDynamicPalette from user somehow magically. And how is that going to work? Can we use the asset pipeline? Not exactly. So we have sort of a quote unquote static context in the Tilt template for SAS Rails. So SAS Rails, it's a gem that you normally have bundled
with your Rails app that gets SAS running in the asset pipeline, and it defines this Tilt template, which is responsible for rendering out the SAS. And we're kind of locked in whatever it's doing there. We would have to do some hackery to get it to work in
a dynamic way like we'd like. So that's not going to work. Oh, and assets, they're pre-combobulated for production. So yeah, asset pipeline is not going to work here. So we need some sort of render class for dynamic content that we're going to have to write. So this is where SAS engine will come to the rescue.
So SAS engine is the actual engine where you render out your CSS based on a CSS or SAS template. So we'll have this SAS custom palette class we'll define. And the first thing, we're going to define this template string.
And we'll do that because it's not going to change. We really don't want to throw another file on the file system to read in just to reuse this in a dynamic context. So we'll just set this template constant. And you'll notice there it's going to call a get custom palette function in SAS. So we're going to take in our color.
We're going to set it as an instance variable. We'll have a render method, which is basically going to delegate to the SAS engine. Pass in the template. We pass in some SAS custom options. And we call a render. So there at the bottom, what's up with these SAS custom options? So the first couple options, pretty straightforward.
Syntax SCSS, that's usually the more popular syntax people like. Style expanded, that's just for pretty printing your CSS. And then that last option, notice, it's called custom. And if you look at SAS's documentation, they mentioned this is specifically what we need in this context.
If you want to inject some sort of custom data to your SAS style sheets, then you pass it in there. So I'm going to pass in a hash, and it's going to basically have whatever our custom seed color is. So we needed to find that get custom palette function. Remember, we need to add a method to SAS script
functions. So it's pretty similar to what we did in the last example. This time, though, notice that we're going to call this options method. And we're going to pass in the custom key and then the color key. So options is available to you inside these SAS methods
based on whatever data you injected. So again, we'll wrap that in a color. Then we're going to create this factor variable. And so basically what I want to do is I just want to create 20%. So I pass in to the number type 20, and then the percent symbol, which is sort of like, here's my unit
for this number. And then I'm going to generate a palette where I'm going to lighten the color by 20%. And then the other color will darken it by 20%. And the lighten and darken functions, those are built into SAS, so that's how they're available there as well. And finally, pass it again into a list and return it.
So finally, what we need to do is we've got to get this rendering from the controller. So we instantiate our new class, pass in params custom color, and then we render out the CSS. We'll try it out. We'll make an HTTP request. And SAS syntax error, file to import, not found or unreadable.
So what happens normally when you're working in a language you have to compile or render? What do you normally need? There's always a load path. And we forgot that. So let's go back and modify this, because we need this load path because it needs to think, in some sense, it's
just like a static style sheet in the asset pipeline. So we're going to add in a new option to our SAS custom options called load paths. And if you look at the method for that, we're basically just, in this case, passing in an array containing one directory, which is app, assets, style sheets, includes. And that's where I'm going to store my UI file.
So let's try that out. And I actually have a demo, just to kind of highlight this at a low level. So what I have here is a pretty simple app I put together. It's got the Hello World text. And I'm going to pass in a color.
And then it's going to render that lightened color as the background for Hello World. And it'll make the text color of Hello World that darken.