#I’ve already been compared to Syntax so we’ll see what that’s about
Explore tagged Tumblr posts
absoluteocellibehavior · 10 months ago
Text
13 years ago I was bright-eyed watching the pilot of Ninjago.
Now, I am once again hooked and cheering on little legos as an adult.
How time flies, huh?
Bittersweet <3
55 notes · View notes
lingthusiasm · 4 years ago
Text
Transcript Episode 47: The happy fun big adjective episode
This is a transcript for Lingthusiasm Episode 47: The happy fun big adjective episode. It’s been lightly edited for readability. Listen to the episode here or wherever you get your podcasts. Links to studies mentioned and further reading can be found on the Episode 47 show notes page.
[Music]
Gretchen: Welcome to Lingthusiasm, a podcast that’s enthusiastic about linguistics! I’m Gretchen McCulloch.
Lauren: I’m Lauren Gawne. Today, we’re getting enthusiastic about adjectives. First, we now have masks to match your scarves, mugs, and notebooks in Lingthusiasm IPA, syntax, and esoteric symbol designs.
Gretchen: If you want a bit more Lingthusiasm as you go about your everyday life, that is a thing you can do. They’re available in many colours. You can go to lingthusiasm.com/merch.
Lauren: I’m interested to see whether prefer to colour coordinate their facemasks with their scarves or if contrasting colours is the way to go.
Gretchen: Stay tuned! We will report back on the Lingthusiasm fashion statement. Also, this month’s Patreon bonus episode is about doing linguistics communication on a shoestring –Bonus 42 – which means there’re 41 additional bonus episodes if you’ve run out of Lingthusiasm to listen to. There’s way more where that came from at patreon.com/lingthusiasm. It’s got a bit of bonus Lingthusiasm origin story because, spoiler, we started our ling comm projects on a shoestring as well.
Lauren: Absolutely. The ling comm on a shoestring episode came together because we’ve been talking to our wonderful linguistics communication project, LingComm, grantees. We realised that it’s the kind of information that’s useful whatever project you’re starting or if you wanna know how we got started doing linguistics communication.
Gretchen: It can probably be cross applied for communicating about other types of topics as well but, hey, we’re linguists, so we’ll call it “ling comm.”
Lauren: Talk about what we know.
[Music]
Gretchen: Lauren, I have a game for you.
Lauren: I love games.
Gretchen: I’m gonna give you a word and then you say whatever word you think of quickly after that.
Lauren: Okay.
Gretchen: Let’s start with “red.”
Lauren: Blue.
Gretchen: Big.
Lauren: Small.
Gretchen: Fast.
Lauren: Slow.
Gretchen: Loud.
Lauren: Quiet.
Gretchen: Online.
Lauren: Offline?
Gretchen: Afloat.
Lauren: “Asink”? What is the opposite of – I don’t know what the opposite of “afloat” is.
Gretchen: “On shore,” “on board,” I dunno.
Lauren: Sure.
Gretchen: I didn’t think through that one very deeply.
Lauren: I’ve been doing so many of these in children’s picture books at the moment. It’s always a great delight.
Gretchen: These words are – or at least mostly, with the exception of “asink,” perhaps – these words are mostly adjectives, which is the kind of word that you may have learned if you played Mad Libs as a hobby like I did growing up – is a word that describes things.
Lauren: I feel like that’s a good start for what an adjective is in terms of you just need a pithy definition. But I feel like these words all have more things in common than just that.
Gretchen: The thing that I find really interesting about adjectives as a category is that they’re one of those categories that seems like it gets passed down to us from the descriptive grammatical tradition. When you start looking at it more closely, it breaks apart really quickly. There are more differences and more similarities in other types of categories. It really starts to make you question the notion of parts of speech. When linguists talk about diagnostics for adjectives, in English, sometimes we diagnose adjectives by saying, okay, you can add endings like “-er” or “-est” on them or use words like “more” and “most” with them to make comparatives and superlatives. You can have something be “redder” or “bluest” or “bigger” or “smallest,” “louder,” or “quieter.” It doesn’t always work though.
Lauren: “More online,” “most online.”
Gretchen: Fair enough. “More afloat,” “less afloat,” “afloater.” Adjectives are words that they have this descriptive property, but they also have this morphosyntactic property that they can be compared to degrees like other adjectives.
Lauren: Once you start realising this is something that adjectives do consistently in English, but other word classes don’t, these “-er” and “-est” suffixes can be used to figure out what isn’t an adjective as well.
Gretchen: If we have a word like “dog,” and I don’t think there is “This dog is ‘dogger’ than this other dog.” “This is the ‘doggest’ dog.”
Lauren: Definitely not in standard English. I think it’s a great example of how we can be playful, but I don’t think it would come off as a very standard form. Or we wouldn’t have like, “You are more ‘danciest.’”
Gretchen: “The ‘dancest.’”
Lauren: “You are the most ‘dance’” doesn’t work because –
Gretchen: I mean, you can be a “dancer,” but that doesn’t make you more “dance” than the other person if you’re a dancer. That’s a different kind of “-er.”
Lauren: You’re a dancer, but I’m the “dancest.”
Gretchen: That sounds like an invitation to a dance off! Yes, I mean, you can do these, but they very clearly have this playful quality that “fast/faster” is just like, yep, you can do that. Whereas, “dancer” or “dancest” has this playful quality that you can do it if you wanna have a bit of fun, but it’s not something that’s already part of the canon of things that people typically say in English.
Lauren: This is why we refer to them as diagnostics in the way that we take a temperature on a person to see if they have a fever, we can use these morphemes to test whether a word is an adjective in English or not.
Gretchen: Or to have the weird fun of making something into a different lexical category than it had previously belonged to. If I wanna say, “Oh, this thing is ‘funner,’” like, hey, that’s a bit of fun you can have with lexical conversion.
Lauren: Are lexical conversations the “funnest” thing you can do? I think so.
Gretchen: They are the “funnest.” There are other ways of doing this. That’s a test you can do with putting endings on the word, and you can also do tests by what kinds of sentences you can put it in. If you have something like, “the red car” or “the big car,” then if you wanna test, oh, does “dance” work in there – “the dance car.” Kind of? Again, it sounds like maybe you’re having a bit of fun with the language. Or “the dog car” – it’s an interesting example because if you take a word like “the doghouse,” right, “dog” is clearly describing “house” there. I think that’s one of the issues that confuses people when you’re talking about adjectives because you can use other kinds of words to describe something or to modify something like “doghouse” or “dance” – I feel like a “dance car” – I dunno, there’s a “party bus.”
Lauren: The dance car is the budget version for when you only have a couple of friends.
Gretchen: Or maybe it’s a car that can dance itself. You can be a “partier,” but you don’t have a “partiest,” like, “This is the ‘partiest’ bus,” “This is the ‘dancest’ car.” It can let us do these diagnostics language-internally and figure out here’s what’s going on in English, here’s what’s going on with this particular word. Where, if we wanna try to force it into the mould of being really adjective-y, then we can do it, but it’s very clearly playful. Whereas, if we make this one into a very adjective-y mould, it’s like, yep, okay, lots of people are already doing that.
Lauren: We’ve been using the “-er” comparative and the “-est” superlative suffixes to tell if something is an adjective, but we can also use a negative diagnostic to check if something is definitely not one of the other word categories.
Gretchen: Right. If you have a word like “party” or “cake,” which we know is a noun, one of the things that nouns can do is nouns can become plural. You have “cakes,” you have “parties” – this sounds like a great afternoon. I’m having the party cake.
Lauren: But you can’t have “bigs.” You can’t use the plural on an adjective.
Gretchen: Right. “Bigs” and “smalls” and “reds.” If you do, it’s kind of because you’re actually treating this adjective as a noun. Sometimes that means – so if I’m doing laundry, I can be like, “Oh, I’m gonna put the reds in this pile and the blues in that pile.” Now, I’ve taken these words that are traditionally adjectives and I’ve converted them into nouns, which is something that people do pretty regularly. This isn’t as playful because people have already done it. And, oh, now I’m actually using this adjective as a noun. English is a language that’s very prone to bringing words to cross over into other lexical categories. Many other languages also do this. It’s something that we miss when we talk about, “Oh, ‘red.’ It’s an adjective,” because you can sometimes use it as a noun. If you talk about like, “I’m gonna wash all the reds together,” you’re using it as a noun there. It’s not that “red” is always an adjective, it’s most canonical form is an adjective in the same way that you can make “This is the ‘partiest’ bus I’ve ever seen.” If you wanna make that into an adjective, you can.
Lauren: I used to get very anxious about this because I liked just being like “These words are adjectives and these words are nouns.” Once I got comfortable with the diagnostic approach of just looking what a word is doing in the particular context it’s being said, it’s actually a lot more liberating and relaxing to be like, “I will just accept this word on the terms that it arrives at me.” I can look at where it is in the word order because that’s important for English. I can also look at what suffixes it has because that’s also useful for English. I can use these criteria every time. I don’t have to remember a list of what’s an adjective and what’s a noun and what’s a verb. I can just use these criteria that I know when I come across an example.
Gretchen: I think it’s one of the things that distinguishes a linguistic approach to grammar from a “I’m taking this high school English class” approach to grammar because I definitely remember being taught, okay, if you wanna know if something’s an adjective, you can look it up in the dictionary, and the dictionary will tell you. This, of course, raises the very obvious question of, “Well, how did the dictionary makers know that this was an adjective? Who decided that?” Dictionaries are great. I’m not anti-dictionary. But if you’re always looking for external authorities for something that you can actually logic out for its principles, it’s unsatisfying. Whereas, being able to actually deduce, “Oh, I know this is an adjective because I’ve run it through these tests,” let’s you feel like you’re figuring something out about that world. It’s the appeal of doing a logic puzzle as opposed to being told like, “Here’s what the sudoku looks like. If you wanna know what the correct answer is to the Sudoku, you just look it up.” It’s like, well, you could actually just do the sudoku and then you could figure it out. That’s more fun than looking up the answer to the sudoku.
Lauren: Yeah. I enjoy being a part of speech detective and figuring out what a word is doing in a sentence using the linguistic evidence that I have.
Gretchen: Similarly, we have existing diagnostics around verbs. Verbs in English, when they’re in the third person singular, often have this other S ending that’s not plural. If I say something like, “She bigs” or “She reds” or “She blues,” this is very clearly being jocular with language almost to the point of incoherence because I’m not quite sure what any of those mean.
Lauren: I guess you could say, “She bigs herself up” and in that complex structure it’s the “big” that takes the plural?
Gretchen: Totally. I mean, I don’t know if that’s an idiom that I have but, when you say, I’m like, “Oh, yeah. Sure.”
Lauren: I’ll accept that. It’s these edge cases – every time you’re like, “I figured out what this category is,” and then you find these edge cases, and then you find the edge cases to the edge cases, and then someone will have written their whole PhD dissertation on an edge case of the edge case, but that is what makes language so fun to play with.
Gretchen: Absolutely. I think if I wanted to make these colour terms into verbs, I’d really wanna add a suffix at that point. “I’m gonna ‘redden’ my shirts by washing them in with the reds.” Sometimes, we just make something into a different part of speech by treating it as if it is, and then it is that way. Then, sometimes we add a suffix, or we add something else to it that makes that conversion happen. Maybe it’s because “redden” exists that it’s difficult to say like, “I ‘red’ the shirt by washing it with the reds.”
Lauren: Once you realise how effective this adding suffix morphemes to words to create new words and new word categories is, you’re like, “Ah, this is how English has 100,000 or 200,000 words,” or whatever people say. Because any noun, if you are a creative enough English speaker, can be adjectivised with the right amount of creative use of the resources that you already have.
Gretchen: Yeah. I mean, I just said the “really adjective-y adjectives,” which makes “adjective,” which is itself a noun, into an adjective. Or it can be “adjectivised,” which then makes it into a verb.
Lauren: Then we can talk about the “adjectivisation” of nouns.
Gretchen: Right. We could talk about “adjectival,” which is the adjective of “adjective.”
Lauren: Yes.
Gretchen: Or the adjectival form of “adjective” if you will. I think we’re really rapidly approaching the place where “adjective” doesn’t actually feel like it means anything anymore, just in the sense of we’ve been saying the sounds /æ/ /d͡ʒ/ /dɪk/ /tɪv/ too many times in a row.
Lauren: I’m really grateful that we have the diagnostic criteria to know that it does actually mean something in English as a category. This is where your native speaker intuitions or finding a speaker of a language to consult their intuitions is really important because, as we’ve already said, there’s a difference between forms that we recognise as people regularly using and ones that we’re just making up for creativity sake for this episode. There are lots of other intuitions that people have about categories like adjectives that they may not have consciously ever reflected on. I think the order of adjectives is definitely one of those things.
Gretchen: Ooo! Is this the “big red car” versus “red big car” thing?
Lauren: Yes. I think of it as the “iced tea” phenomenon, personally.
Gretchen: I could go for some iced tea right now.
Lauren: Sure. If you would like a flavour of iced tea, what type of iced tea would you like?
Gretchen: I dunno. Maybe I’ll take a lemon iced tea.
Lauren: I always used to order lemon iced tea in Singapore. It took quite a while, while I was living there, is realise that I was in this weird negotiation with people because I would order a lemon iced tea and they would say, “Yes, one iced lemon tea for you.” “Lemon iced tea” is the phrase that I am used to. It took a long time for me to actually remember to order an “iced lemon tea.” I figured out it was because, for me, “iced tea” was the genre. That’s the minimal unit. Then, I would add “lemon” as a second adjective to modify that because I could have lemon iced tea or peach iced tea or any other delicious flavour of iced tea.
Gretchen: Mango iced tea or something.
Lauren: Whereas, for Singaporeans, it was the fact that it was lemon tea or milk tea or black tea –
Gretchen: Yeah, okay, and then you could have hot milk tea or cold milk tea, hot lemon tea or iced lemon tea.
Lauren: Mm-hmm. In this case, the adjective order was dependent on what we thought we were modifying to begin with.
Gretchen: That’s really neat. There’s this meme that circulates the internet every so often pointing out that people say “the big red balloon” or the “the four big red balloons” or “the four big old round red rubber toy balloons,” and this sounds like a lot of description to go to when I’m talking about balloons, but it sounds unremarkable to you. Whereas, if you put it in another order like, “the toy rubber red round big four old balloons” –
Lauren: I can actually feel you pause and mentally process that.
Gretchen: The ironic thing is, is I’m reading it out loud and yet it’s still so difficult to say out loud from a page. Because there’re certain conventions about orders that people put adjectives in, and you don’t even think about this because you just do it instinctively. It seems to often work fairly similarly across languages, which is kind of interesting.
Lauren: Even now that we’ve just figured out what adjectives are, there’re actually sub-categories within adjectives. Are they describing different properties of something? Is that where they come from?
Gretchen: Yeah. For example, people tend to put size before colour – that’s your “big red” thing. Or objective or subjective opinion can sometimes go – it can go in a couple different places. You have “big bad wolf,” not “bad big wolf.”
Lauren: But maybe there’s a bad small wolf, just to go back to the lemon iced tea situation.
Gretchen: Well, and that’s the thing. There is some sense in which there’s a bit of a default order, but there’s also a sense in which “the bad big wolf” and “the good big wolf” – you could use that order if you wanted to have a direct contrast there. So, in addition to the fact that, hey, the order you put adjectives in is actually more regular and more complicated than you thought about it – there’s revelation Number 1 – revelation Number 2 is, you can break it still. You can do other things with it than this pattern you didn’t realise you were following. You can follow this second pattern you also didn’t realise you were following.
Lauren: It’s adjective awareness all the way down.
Gretchen: Yes. One version of this order that people have described is: quantity; objective/subjective opinion; size; age; shape; colour; quote-unquote “real” adjectives or adjectives not otherwise specified; and purpose. That’s something like “rubber” for the adjective not otherwise specified – material, maybe – purpose, something like a toy. That is one order you could come up with. It words fairly well if you’re just substituting “red” and “blue” with each other, or “old” and “young” with each other, in respect to these kinds of things. You can keep stacking adjectives and see which orders break. Of course, sometimes, if you put “good” in there, it’s not necessarily gonna work the same way as “high-quality,” even though those are both opinions. You can start creating a really elaborate taxonomy of adjective orders, and you can kind of get somewhere, but you’re also like, “Where am I even going?”
Lauren: Obviously, intuition is part of this because we found it easier to process one order than the other, but linguists also draw on corpora. People will look at how adjectives have been ordered in speech to look at which ones people prefer to go before or after. It’s actually incredibly rare to get seven adjectives. It’s really rare for people to describe a balloon in that much detail.
Gretchen: Well, and it’s interesting that we have intuitions about how these seven adjectives can be ordered even though it’s very rare that we actually say seven adjectives in a row like that. That’s kind of neat. In languages, languages like French, which often puts the adjectives after the noun, you may get the same order but in the inverse. The order is based on what’s closest to the noun not the linear left to right order or first to last order. It can be based on what’s closest to the noun and build outwards in the other direction. Although, French has this interesting complication which is that some of its adjectives, “big” and “small” – “grande,” “petite” – tend to go before the nouns, whereas most of its adjectives go after. You have this interesting intersection there.
Lauren: Our English diagnostic criteria for adjectives going before a noun is not gonna work as neatly for French.
Gretchen: Right. One of the things that you learn in French class is like, “Oh, there’re these two classes of adjectives. There’s the class that goes before the noun and the class that goes after.”
Lauren: Cool.
Gretchen: Or, for some of them, if you put this adjective that conventionally goes before the noun and sometimes it goes after, it means something slightly different when it goes after. Maybe it means something a little bit more literal or something. The question of which part of speech categories are the categories that we actually should use and which ones are just spurious differences that don’t really matter because it’s not part of the real categories – it turns into this giant can of worms when you start opening it. Because, in French, we could say, “Oh, well, we have adjectives. Adjectives are adjectives. Surely there are adjectives, right?” But then why not, in French, have two different categories of these modifiers that go before the noun versus these modifiers that go after the noun? Why unify them both under “adjectives”? They don’t behave the same way.
Lauren: Do they behave the same way in other ways?
Gretchen: They do behave the same way in other contexts. You can describe them with comparatives and superlatives kind of like you can in English. It’s not a suffix. It’s a different word like “more.” But one of the key things is that they agree in gender and number with the nouns that they modify. If you talk about “a blue car” versus “blue cars,” you’re gonna put that extra S silently – in the writing, but not necessarily in speech – on the word “blue” as well as the word “car.”
Lauren: Okay.
Gretchen: This is much easier to see in a language like Latin, which actually pronounces these differences, versus French where it’s kind of fossilised and maybe fake – I dunno, it depends on who you ask – because it’s mostly there in the writing at this point. In Latin, it’s definitely very actively there in the actual speech. It’s actually still pronounced. In Latin, any sort of ending change that you do on the nouns – if you make it plural, if you make it possessive, if you make it the subject or the object of the sentence – all of these types of changes that you could do to the noun you have to do with whatever adjectives it goes with. The big way that you can tell that something is an adjective is because it’s doing all this stuff to match its noun. If you read Latin poetry, you can see the noun and the adjective can be split apart on different lines, and you can tell that they go with each other because they have matching endings.
Lauren: It’s really cool that adjectives have a noun-y property in French because there’s a language in Nepal called Manange where some of the adjectives have a verb-y vibe rather than a noun-y vibe. I know about this because in a grammatical description by my colleague and collaborator Kristine Hildebrandt, she talks about – they have this really small set of adjectives that behave more like adjectives as we think of them in English, but then they also have this set that they come from verbs. You can see how they’re related.
Gretchen: An English version of that might be if I say like, “The cat is running,” I could also talk about “the running cat” or “the walking cat,” where “run” and “walk” are canonically verbs, but you can also use them in an adjective-y sort of way. You don’t get to talk about “the ‘runningest’ cat” or “the ‘walkinger’ cat.” You kind of could.
Lauren: You can talk about the “more cooked cake” – “Mine turned under baked, but yours is more cooked.” But, anyway, you absolutely couldn’t use the “Look at if the adjective is doing noun-y things” criteria that’s very important for French. You can’t use that for Manange. You have to look at how they relate to the verbs instead.
Gretchen: Well, and it’s interesting because, doing the research for this episode and looking at Latin in a bit more detail, it turns out that Latin grammarians actually didn’t distinguish in the same way between nouns and adjectives at all. They talked about this broader category of “nomin” or “names” of which both nouns and adjectives were sub-categories. You had your substantive nouns and your adjectival nouns. These are both sub-categories of the general categories of nouns. Then verbs was its whole other thing. In some respects, I like to think of them as “adje-verbs” and “adje-nouns.” You have your adjectives that work like verbs do and your adjectives that work like nouns do. This is true of Algonquian languages as well is you have in these languages “to be red” or “to be big” is a verb. Instead of saying, “This house is big,” you say, essentially, “The house bigs” or “The house reds,” and that means, “It is big” or “It is red.” It’s all one word.
Lauren: Cool. That’s very verb, as opposed to the Manange which are kind of verb-y.
Gretchen: Yeah. They conjugate like verbs. The verbs get different types of endings and so on. They really act like verbs. Whereas, the nouns do a different thing. They have the endings like verbs do. It’s interesting to see – okay, the idea that adjectives exist. You can find evidence in English that they’re distinct from both verbs and nouns. They can do different types of things. But depending on the language, something that means essentially the same thing – like “red” or “big” or something which seems very descriptive-y – can, in some languages, have formal properties that makes it more like a verb, and then other languages have formal properties that makes it look like a noun, or neither of the above. I went and looked at the book Describing Morphosyntax, which is a book that tries to do a –
Lauren: Here’s all the possibilities.
Gretchen: Yeah. It’s a book that tries to catalogue the possibilities for what languages can do, which of course is biased towards which languages have been previously described, but it does give you a bit of a picture of what some languages do at least. They actually break down five different types of ways you could treat adjectives.
Lauren: Okay. Here are five common ways, if we look across the world’s languages, adjectives tend to exist.
Gretchen: Right. They call them “property concepts” because it’s not clear that all of them are actually adjectives.
Lauren: Okay.
Gretchen: We’ve talked about three of them already. One is property concepts could be verbs. The second is property concepts could be nouns. The fifth is there’s a distinct class of adjectives for property concepts.
Lauren: I love that’s the fifth. The thing that we think of as the most obvious is like, “Oh, and also this thing.”
Gretchen: The other two are – sometimes property concepts are treated as nouns and sometimes they’re treated as verbs depending on the demands of discourse. The example that this book has is in Dutch, but I’m more familiar with the German case which works in the same way, I think. This was one of those weird facts you have to learn about German adjectives if you learn German adjectives in school. Thy way that they articulate it in this book was not the way that I had learned this. It was just like, “Here’s this class of adjectives and it does several different weird things.” It’s very cool when you think about it in this way, which is that when the adjective goes before the noun – if you have something like “a red cat,” “a red car,” which is “eine rote Katze,” “ein rotes Auto.” “A red balloon” – “ein roter Ballon.” In that case, the adjective, “red,” has a different form depending on which noun it goes with. It acts like a noun because it gets all these noun endings depending on the gender. But if you say, “The cat is red,” “The car is red,” “The balloon is red” – “Das Auto ist rot.” You don’t put the ending there. You just have the bare form of the adjective. In that sense, it’s acting more verb-like because it doesn’t do the same gender agreement that it does when it’s before the noun. This was taught to me as like, “Here’s this thing you have to memorise,” but to think about it in terms of a typological perspective of maybe adjectives are fake and these words are sometimes acting as nouns and sometimes acting as verbs depending on other things in the discourse, it’s just a really interesting proposal. German speakers probably think that they have adjectives, but it’s an interesting formal proposal.
Lauren: I like it as a way to re-think something you take for granted.
Gretchen: Because it is true that sometimes they really seem to be very noun-y and they get these endings that the nouns get. Sometimes, they don’t get these endings. There’s also an extent to which they don’t really act like verbs because verbs get endings depending on what – if they were being really verb-y, you should have like, “You ‘red,’” “Du ‘rotest,’” which that doesn’t – “Du ‘rotst’” – that doesn’t exist. They don’t act fully like verbs, but they could act in the same way that you can say, “This is open,” “This is closed,” “This is opened,” “It is closed.” It could be some sort of verbal participle thingy. I dunno. It’s an interesting way of pointing out that even the diagnostics that say, “It takes on morphosyntactic properties of one type of part of speech, therefore it must belong to the same category as that part of speech.” If you have a case where sometimes it has the same endings and sometimes it doesn’t, then there are two things going on.
Lauren: Hmm. You’ve talked about four out of five possibilities for how things we think of as adjectives occur across the world’s languages. What is the fifth?
Gretchen: The fifth one is also a part-time thing which is that some property concepts get treated as nouns and other ones get treated as verbs.
Lauren: Right. So, kind of the opposite.
Gretchen: Right.
Lauren: Okay. This is our Manange example where you have that very small set that act as adjectives in a particular way and you have a set that act as more verb-y adjectives.
Gretchen: Yeah. For example – and I don’t know if this is true of a particular language – you could say, maybe, colours and numbers in this language get treated as verbs but sizes and qualities get treated as nouns or vice versa or some sort of distinction like that. The example in this book is with Yoruba, and I don’t know enough Yoruba to have a concrete example of how that works.
Lauren: It does exist in real languages. That’s good enough evidence for me.
Gretchen: It kind of takes us to this question which, you know, is also a question, if we look back at the Latin based or Greek based – because Greek did the same thing as Latin where it lumped nouns and adjectives together for, again, really good language internal reasons that they had the same sets of endings – of, is the class of adjectives even valid? Is it even really a thing when you start looking at the different types of evidence for a distinct class of words, in this case, across different languages?
Lauren: This brings us back to that question of those diagnostic criteria and the ways of testing if something is an adjective or maybe a noun or a verb that we talked about in more detail for English and a little bit of detail for other languages which is that you need to figure out the criteria that you’re using for diagnosis in each language. You can’t just come in with the English criteria and try and apply them to Yoruba or Manange or French because it won’t work.
Gretchen: It begs the question – in English, there’s an established grammatical tradition of saying, “Here are the diagnostic criteria for adjectives” and if you’re gonna work in English, it’s useful to know what the rest of the literature says for what adjectives are. If you’re working in a language where there hasn’t been this descriptive grammatical tradition, you’re coming in and saying, “Okay, so, first thing I need to figure out – are there any diagnoses that could prove that this is a different thing? What would it mean to be different? What are the language-internal things that could prove that some set of unknown words is different from some other set of other unknown words? I don’t know what the words are in each of these categories yet.”
Lauren: Yes. I remember doing this for Yolmo. There’s a bit of flexibility about whether an adjective can go before a noun or after a noun. They seem to mostly go before, I think, but I never actually – with the data that I had – managed to tease apart if it was a thing that was completely free or if it was because people were focusing on a particular bit of information and they wanted that at the start or the end. Going back to that thing about corpora, one of the examples that I have in the descriptive grammar of Lamjung Yolmo that I wrote is in there because I was just so excited to have a spontaneous example of someone saying a sentence that had three adjectives in it.
Gretchen: Because it’s so rare!
Lauren: Getting people to say something off the cuff with seven adjectives in it is so rare – impossibly rare. Even just having three adjectives I was like, “It’s so pretty. I have no reason to put it in the grammar except that there’re three adjectives here.” I had to start from scratch with this language – well, start with the existing literature because why make life hard for yourself – and figure out my own criteria for whether the category of adjectives existed at all to write about them in grammar and how to explain them.
Gretchen: But the existing literature doesn’t look something like the 1,000-plus page Cambridge Grammar of the English language that has everything described in exhaustive detail plus the hundreds of other books that are written about it. It’s like, “Oh, there are two books. Okay, that’s fine.”
Lauren: There’re a few things around, yes. It’s these edge cases on edge cases that we’ve been talking about, which is why something like the Cambridge Grammar of the English Language doesn’t just have, “Adjectives describe and modify nouns.”
Gretchen: That’s it. The one-page Cambridge Grammar of the English Language. That’s all that’s there. There’s 1,000 pages of, I dunno, probably 50 or 100 pages about adjectives in CGL. I haven’t checked.
Lauren: Looking at the variation across languages in how what we think of as adjectives behave and how you have to use language specific criteria for deciding if there are adjectives and what they look like brings us to a bigger philosophical question as to whether adjectives exist in Language as a thing at all – once we start looking at all the variation across the world’s languages.
Gretchen: And even more broadly, whether it’s legitimate to look at multiple languages and try to apply the same sets of categories. Is it legitimate to try to say that languages have nouns and languages have verbs? Even if we can establish maybe noun-hood and verb-hood – because those are, I dunno, fairly basic – does that mean that the more edge case-y categories like adjectives or adverbs or prepositions or something like that, which can sometimes be done with other types of grammatical features, do those exist? Is it even legitimate to try to cross apply these categories in languages? It’s an ontological question that doesn’t have an easy answer.
Lauren: This is actually an ongoing question in linguistics. It doesn’t have an easy answer. People are still grappling with this idea of language internal categories versus language general categories.
Gretchen: There’s a large extent to which the categories that we think of as basic, primary categories – nouns, verbs, adjectives – are inherited from a particular type of intellectual tradition of looking at languages. I mean, kind of the Greek and Latin one except not entirely because they didn’t actually necessarily think adjectives were entirely their own thing.
Lauren: What a revelation.
Gretchen: It comes from a particular grammatical descriptive tradition. Perhaps, if we’d started with a different language, we might’ve said, ah, well, a really important distinction is – let’s say you’re gonna be French – whether it goes before the noun or after the noun. Actually, this is a fundamental distinction and we need to go looking for this distinction in a whole bunch of other languages because we have this easy diagnostic for it in French. Surely, there’s some sort of fundamental ontological distinction between this set. So, where do you make your fundamental ontological distinctions and where do you say, “Oh, actually, these are just two sub-types of adjectives” or “These are two sub-types of verbs. Some of them just tend to be adje-verbs.”
Lauren: This ongoing debate about word categories and their existence across language is so long-standing in linguistics that the two different sides of this argument as affectionately known as “lumpers” and “splitters.”
Gretchen: Great names.
Lauren: Great names. Whether you lump words together that may have been across what people have more lately decided as separate categories. Those original Latin grammarians lumping what we think of as nouns and adjectives together – great lumpers. We’re much more splitter-y in our approach these days.
Gretchen: By comparison, we’re much splitter-y. Whereas, if we were to say, oh, it turns out that the kinds of things that can go before a noun and after the noun are something different, we could become even more splitter-y if we wanted to. You can find people who’ll argue for a lumpier approach or a splittier approach within the same language, sometimes using the same data to say, “Oh, well, there are some similarities or there are some differences and it depends on whether you think the similarities are more important or the differences are more important for whether you’re gonna argue for one or the other.” I love how it destabilises this – we think of, again, as this fairly intuitive notion of an adjective to say, “Well, maybe adjectives aren’t a thing” or “They’re not a thing in all languages” or “The evidence for them is different depending on what language you’re looking at.”
[Music]
Lauren: For more Lingthusiasm and links to all the things mentioned in this episode, go to lingthusiasm.com. You can listen to us on Apple Podcasts, Google Podcasts, Spotify, SoundCloud, YouTube, or wherever else you get your podcasts. You can follow @Lingthusiasm on Twitter, Facebook, Instagram, and Tumblr. You can get IPA scarves, masks, and ties, and other Lingthusiasm merch at lingthusiasm.com/merch. I tweet and blog as Superlinguo.
Gretchen: I can be found as @GretchenAMcC on Twitter, my blog is AllThingsLinguistic.com, and my book about internet language is called Because Internet.
Lauren: It’s now available as a paperback.
Gretchen: Yes, it is. Have you listened to all the Lingthusiasm episodes and you wish there were more? You can get access to 42 bonus episodes right now to listen to at patreon.com/lingthusiasm or follow the links from our website. Patrons also get access to our Discord chatroom to talk with other linguistics fans and other rewards, as well as helping keep the show ad-free. Recent bonus topics include linguistics communication, language and music, and doing linguistics with kids. Can’t afford to pledge? That’s okay, too. We also really appreciate it if you can recommend Lingthusiasm to anyone who needs a little more linguistics in their life.
Lauren: Lingthusiasm is created and produced by Gretchen McCulloch and Lauren Gawne. Our senior producer is Claire Gawne, our editorial producer is Sarah Dopierala, and our comms producer is Eleanor Bally. Our music is “Ancient City” by The Triangles.
Gretchen: Stay lingthusiastic!
[Music]
Tumblr media
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
6 notes · View notes
suzanneshannon · 3 years ago
Text
Using Absolute Value, Sign, Rounding and Modulo in CSS Today
For quite a while now, the CSS spec has included a lot of really useful mathematical functions, such as trigonometric functions (sin(), cos(), tan(), asin(), acos(), atan(), atan2()), exponential functions (pow(), exp(), sqrt(), log(), hypot()), sign-related functions (abs(), sign()) and stepped value functions (round(), mod(), rem()).
However, these are not yet implemented in any browser, so this article is going to show how, using CSS features we already have, we can compute the values that abs(), sign(), round() and mod() should return. And then we’ll see what cool things this allows us to build today.
Tumblr media
A few of the things these functions allow us to make.
Note that none of these techniques were ever meant to work in browsers from back in the days when dinosaurs roamed the internet. Some of them even depend on the browser supporting the ability to register custom properties (using @property), which means they’re limited to Chromium for now.
The computed equivalents
--abs
We can get this by using the new CSS max() function, which is already implemented in the current versions of all major browsers.
Let’s say we have a custom property, --a. We don’t know whether this is positive or negative and we want to get its absolute value. We do this by picking the maximum between this value and its additive inverse:
--abs: max(var(--a), -1*var(--a));
If --a is positive, this means it’s greater than zero, and multiplying it with -1 gives us a negative number, which is always smaller than zero. That, in turn, is always smaller than the positive --a, so the result returned by max() is equal to var(--a).
If --a is negative, this means it’s smaller than zero, and that multiplying it by -1 gives us a positive number, which is always bigger than zero, which, in turn, is always bigger than the negative --a. So, the result returned by max() is equal to -1*var(--a).
--sign
This is something we can get using the previous section as the sign of a number is that number divided by its absolute value:
--abs: max(var(--a), -1*var(--a)); --sign: calc(var(--a)/var(--abs));
A very important thing to note here is that this only works if --a is unitless, as we cannot divide by a number with a unit inside calc().
Also, if --a is 0, this solution works only if we register --sign (this is only supported in Chromium browsers at this point) with an initial-value of 0:
@property --sign { syntax: '<integer>'; initial-value: 0; inherits: false /* or true depending on context */ }
This is because --a, being 0, also makes --abs compute to 0 — and dividing by 0 is invalid in CSS calc() — so we need to make sure --sign gets reset to 0 in this situation. Keep in mind that this does not happen if we simply set it to 0 in the CSS prior to setting it to the calc() value and we don’t register it:
--abs: max(var(--a), -1*var(--a)); --sign: 0; /* doesn't help */ --sign: calc(var(--a)/var(--abs));
In practice, I’ve also often used the following version for integers:
--sign: clamp(-1, var(--a), 1);
Here, we’re using a clamp() function. This takes three arguments: a minimum allowed value -1, a preferred value var(--a) and a maximum allowed value, 1. The value returned is the preferred value as long as it’s between the lower and upper bounds and the limit that gets exceeded otherwise.
If --a is a negative integer, this means it’s smaller or equal to -1, the lower bound (or the minimum allowed value) of our clamp() function, so the value returned is -1. If it’s a positive integer, this means it’s greater or equal to 1, the upper bound (or the maximum allowed value) of the clamp() function, so the value returned is 1. And finally, if --a is 0, it’s between the lower and upper limits, so the function returns its value (0 in this case).
This method has the advantage of being simpler without requiring Houdini support. That said, note that it only works for unitless values (comparing a length or an angle value with integers like ±1 is like comparing apples and oranges — it doesn’t work!) that are either exactly 0 or at least as big as 1 in absolute value. For a subunitary value, like -.05, our method above fails, as the value returned is -.05, not -1!
My first thought was that we can extend this technique to subunitary values by introducing a limit value that’s smaller than the smallest non-zero value we know --a can possibly take. For example, let’s say our limit is .000001 — this would allow us to correctly get -1 as the sign for -.05, and 1 as the sign for .0001!
--lim: .000001; --sign: clamp(-1*var(--lim), var(--a), var(--lim));
Temani Afif suggested a simpler version that would multiply --a by a very large number in order to produce a superunitary value.
--sign: clamp(-1, var(--a)*10000, 1);
I eventually settled on dividing --a by the limit value because it just feels a bit more intuitive to see what minimum non-zero value it won’t go below.
--lim: .000001; --sign: clamp(-1, var(--a)/var(--lim), 1);
--round (as well as --ceil and --floor)
This is one I was stuck on for a while until I got a clever suggestion for a similar problem from Christian Schaefer. Just like the case of the sign, this only works on unitless values and requires registering the --round variable as an <integer> so that we force rounding on whatever value we set it to:
@property --round { syntax: '<integer>'; initial-value: 0; inherits: false /* or true depending on context */ } .my-elem { --round: var(--a); }
By extension, we can get --floor and --ceil if we subtract or add .5:
@property --floor { syntax: '<integer>'; initial-value: 0; inherits: false /* or true depending on context */ } @property --ceil { syntax: '<integer>'; initial-value: 0; inherits: false /* or true depending on context */ } .my-elem { --floor: calc(var(--a) - .5); --ceil: calc(var(--a) + .5) }
--mod
This builds on the --floor technique in order to get an integer quotient, which then allows us to get the modulo value. This means that both our values must be unitless.
@property --floor { syntax: '<integer>'; initial-value: 0; inherits: false /* or true depending on context */ } .my-elem { --floor: calc(var(--a)/var(--b) - .5); --mod: calc(var(--a) - var(--b)*var(--floor)) }
Use cases
What sort of things can we do with the technique? Let’s take a good look at three use cases.
Effortless symmetry in staggered animations (and not only!)
While the absolute value can help us get symmetrical results for a lot of properties, animation-delay and transition-delay are the ones where I’ve been using it the most, so let’s see some examples of that!
We put --n items within a container, each of these items having an index --i. Both --n and --i are variables we pass to the CSS via style attributes.
- let n = 16; .wrap(style=`--n: ${n}`) - for(let i = 0; i < n; i++) .item(style=`--i: ${i}`)
This gives us the following compiled HTML:
<div class='wrap' style='--n: 16'> <div class='item' style='--i: 0'></div> <div class='item' style='--i: 1'></div> <!-- more such items --> </div>
We set a few styles such that the items are laid out in a row and are square with a non-zero edge length:
$r: 2.5vw; .wrap { display: flex; justify-content: space-evenly; } .item { padding: $r; }
Tumblr media
The result so far.
Now we add two sets of keyframes to animate a scaling transform and a box-shadow. The first set of keyframes, grow, makes our items scale up from nothing at 0% to full size at 50%, after which they stay at their full size until the end. The second set of keyframes, melt, shows us the items having inset box shadows that cover them fully up to the midway point in the animation (at 50%). That’s also when the items reach full size after growing from nothing. Then the spread radius of these inset shadows shrinks until it gets down to nothing at 100%.
$r: 2.5vw; .item { padding: $r; animation: a $t infinite; animation-name: grow, melt; } @keyframes grow { 0% { transform: scale(0); } 50%, 100% { transform: none; } } @keyframes melt { 0%, 50% { box-shadow: inset 0 0 0 $r; } 100% { box-shadow: inset 0 0; } }
Tumblr media
The base animation (live demo).
Now comes the interesting part! We compute the middle between the index of the first item and that of the last one. This is the arithmetic mean of the two (since our indices are zero-based, the first and last are 0 and n - 1 respectively):
--m: calc(.5*(var(--n) - 1));
We get the absolute value, --abs, of the difference between this middle, --m, and the item index, --i, then use it to compute the animation-delay:
--abs: max(var(--m) - var(--i), var(--i) - var(--m)); animation: a $t calc(var(--abs)/var(--m)*#{$t}) infinite backwards; animation-name: grow, melt;
The absolute value ,--abs, of the difference between the middle, --m, and the item index, --i, can be as small as 0 (for the middle item, if --n is odd) and as big as --m (for the end items). This means dividing it by --m always gives us a value in the [0, 1] interval, which we then multiply with the animation duration $t to ensure every item has a delay between 0s and the animation-duration.
Note that we’ve also set animation-fill-mode to backwards. Since most items will start the animations later, this tells the browser to keep them with the styles in the 0% keyframes until then.
In this particular case, we wouldn’t see any difference without it either because, while the items would be at full size (not scaled to nothing like in the 0% keyframe of the grow animation), they would also have no box-shadow until they start animating. However, in a lot of other cases, it does make a difference and we shouldn’t forget about it.
Another possibility (one that doesn’t involve setting the animation-fill-mode) would be to ensure the animation-delay is always smaller or at most equal to 0 by subtracting a full animation-duration out of it.
--abs: max(var(--m) - var(--i), var(--i) - var(--m)); animation: a $t calc((var(--abs)/var(--m) - 1)*#{$t}) infinite; animation-name: grow, melt;
Both options are valid, and which one you use depends on what you prefer to happen at the very beginning. I generally tend to go for negative delays because they make more sense when recording the looping animation to make a gif like the one below, which illustrates how the animation-delay values are symmetrical with respect to the middle.
Tumblr media
The staggered looping animation.
For a visual comparison between the two options, you can rerun the following demo to see what happens at the very beginning.
CodePen Embed Fallback
A fancier example would be the following:
Navigation links sliding up and then back down with a delay proportional to how far they are from the selected one.
Here, each and every one of the --n navigation links and corresponding recipe articles have an index --idx. Whenever a navigation link is hovered or focused, its --idx value is read and set to the current index, --k, on the body. If none of these items is hovered or focused, --k gets set to a value outside the [0, n) interval (e.g. -1).
The absolute value, --abs, of the difference between --k and a link’s index, --idx, can tell us whether that’s the currently selected (hovered or focused) item. If this absolute value is 0, then our item is the currently selected one (i.e. --not-sel is 0 and --sel is 1). If this absolute value is bigger than 0, then our item is not the currently selected one (i.e. --not-sel is 1 and --sel is 0).
Given both --idx and --k are integers, it results that their difference is also an integer. This means the absolute value, --abs, of this difference is either 0 (when the item is selected), or bigger or equal to 1 (when the item is not selected).
When we put all of this into code, this is what we get:
--abs: Max(var(--k) - var(--idx), var(--idx) - var(--k)); --not-sel: Min(1, var(--abs)); --sel: calc(1 - var(--not-sel));
The --sel and --not-sel properties (which are always integers that always add up to 1) determine the size of the navigation links (the width in the wide screen scenario and the height in the narrow screen scenario), whether they’re greyscaled or not and whether or not their text content is hidden. This is something we won’t get into here, as it is outside the scope of this article and I’ve already explained in a lot of detail in a previous one.
What is relevant here is that, when a navigation link is clicked, it slides out of sight (up in the wide screen case, and left in the narrow screen case), followed by all the others around it, each with a transition-delay that depends on how far they are from the one that was clicked (that is, on the absolute value, --abs, of the difference between their index, --idx, and the index of the currently selected item, --k), revealing the corresponding recipe article. These transition-delay values are symmetrical with respect to the currently selected item.
transition: transform 1s calc(var(--abs)*.05s);
The actual transition and delay are actually a bit more complex because more properties than just the transform get animated and, for transform in particular, there’s an additional delay when going back from the recipe article to the navigation links because we wait for the <article> element to disappear before we let the links slide down. But what were’re interested in is that component of the delay that makes the links is closer to the selected one start sliding out of sight before those further away. And that’s computed as above, using the --abs variable.
You can play with the interactive demo below.
CodePen Embed Fallback
Things get even more interesting in 2D, so let’s now make our row a grid!
We start by changing the structure a bit so that we have 8 columns and 8 rows (which means we have 8·8 = 64 items in total on the grid).
- let n = 8; - let m = n*n; style - for(let i = 0; i < n; i++) | .item:nth-child(#{n}n + #{i + 1}) { --i: #{i} } | .item:nth-child(n + #{n*i + 1}) { --j: #{i} } .wrap(style=`--n: ${n}`) - for(let i = 0; i < m; i++) .item
The above Pug code compiles to the following HTML:
<style> .item:nth-child(8n + 1) { --i: 0 } /* items on 1st column */ .item:nth-child(n + 1) { --j: 0 } /* items starting from 1st row */ .item:nth-child(8n + 2) { --i: 1 } /* items on 2nd column */ .item:nth-child(n + 9) { --j: 1 } /* items starting from 2nd row */ /* 6 more such pairs */ </style> <div class='wrap' style='--n: 8'> <div class='item'></div> <div class='item'></div> <!-- 62 more such items --> </div>
Just like the previous case, we compute a middle index, --m, but since we’ve moved from 1D to 2D, we now have two differences in absolute value to compute, one for each of the two dimensions (one for the columns, --abs-i, and one for the rows, --abs-j).
--m: calc(.5*(var(--n) - 1)); --abs-i: max(var(--m) - var(--i), var(--i) - var(--m)); --abs-j: max(var(--m) - var(--j), var(--j) - var(--m));
We use the exact same two sets of @keyframes, but the animation-delay changes a bit, so it depends on both --abs-i and --abs-j. These absolute values can be as small as 0 (for tiles in the dead middle of the columns and rows) and as big as --m (for tiles at the ends of the columns and rows), meaning that the ratio between either of them and --m is always in the [0, 1] interval. This means the sum of these two ratios is always in the [0, 2] interval. If we want to reduce it to the [0, 1] interval, we need to divide it by 2 (or multiply by .5, same thing).
animation-delay: calc(.5*(var(--abs-i)/var(--m) + var(--abs-j)/var(--m))*#{$t});
This gives us delays that are in the [0s, $t] interval. We can take the denominator, var(--m), out of the parenthesis to simplify the above formula a bit:
animation-delay: calc(.5*(var(--abs-i) + var(--abs-j))/var(--m)*#{$t});
Just like the previous case, this makes grid items start animating later the further they are from the middle of the grid. We should use animation-fill-mode: backwards to ensure they stay in the state specified by the 0% keyframes until the delay time has elapsed and they start animating.
Alternatively, we can subtract one animation duration $t from all delays to make sure all grid items have already started their animation when the page loads.
animation-delay: calc((.5*(var(--abs-i) + var(--abs-j))/var(--m) - 1)*#{$t});
This gives us the following result:
Tumblr media
The staggered 2D animation (live demo).
Let’s now see a few more interesting examples. We won’t be going into details about the “how” behind them as the symmetrical value technique works exactly the same as for the previous ones and the rest is outside the scope of this article. However, there is a link to a CodePen demo in the caption for each of the examples below, and most of these Pens also come with a recording that shows me coding them from scratch.
In the first example, each grid item is made up of two triangles that shrink down to nothing at opposite ends of the diagonal they meet along and then grow back to full size. Since this is an alternating animation, we let the delays to stretch across two iterations (a normal one and a reversed one), which means we don’t divide the sum of ratios in half anymore and we subtract 2 to ensure every item has a negative delay.
animation: s $t ease-in-out infinite alternate; animation-delay: calc(((var(--abs-i) + var(--abs-j))/var(--m) - 2)*#{$t});
Grid wave: pulsing triangles (live demo)
In the second example, each grid item has a gradient at an angle that animates from 0deg to 1turn. This is possible via Houdini as explained in this article about the state of animating gradients with CSS.
Field wave: cell gradient rotation (live demo)
The third example is very similar, except the animated angle is used by a conic-gradient instead of a linear one and also by the hue of the first stop.
Rainbow hour wave (live demo)
In the fourth example, each grid cell contains seven rainbow dots that oscillate up and down. The oscillation delay has a component that depends on the cell indices in the exact same manner as the previous grids (the only thing that’s different here is the number of columns differs from the number of rows, so we need to compute two middle indices, one along each of the two dimensions) and a component that depends on the dot index, --idx, relative to the number of dots per cell, --n-dots.
--k: calc(var(--idx)/var(--n-dots)); --mi: calc(.5*(var(--n-cols) - 1)); --abs-i: max(var(--mi) - var(--i), var(--i) - var(--mi)); --mj: calc(.5*(var(--n-rows) - 1)); --abs-j: max(var(--mj) - var(--j), var(--j) - var(--mj)); animation-delay: calc((var(--abs-i)/var(--mi) + var(--abs-j)/var(--mj) + var(--k) - 3)*#{$t});
Rainbow dot wave: dot oscillation (live demo)
In the fifth example, the tiles making up the cube faces shrink and move inwards. The animation-delay for the top face is computed exactly as in our first 2D demo.
Breathe into me: neon waterfall (live demo and a previous iteration)
In the sixth example, we have a grid of columns oscillating up and down.
Column wave (live demo)
The animation-delay isn’t the only property we can set to have symmetrical values. We can also do this with the items’ dimensions. In the seventh example below, the tiles are distributed around half a dozen rings starting from the vertical (y) axis and are scaled using a factor that depends on how far they are from the top point of the rings. This is basically the 1D case with the axis curved on a circle.
Circular grid melt (live demo)
The eighth example shows ten arms of baubles that wrap around a big sphere. The size of these baubles depends on how far they are from the poles, the closest ones being the smallest. This is done by computing the middle index, --m, for the dots on an arm and the absolute value, --abs, of the difference between it and the current bauble index, --j, then using the ratio between this absolute value and the middle index to get the sizing factor, --f, which we then use when setting the padding.
--m: calc(.5*(var(--n-dots) - 1)); --abs: max(var(--m) - var(--j), var(--j) - var(--m)); --f: calc(1.05 - var(--abs)/var(--m)); padding: calc(var(--f)*#{$r});
Travel inside the sphere (live demo)
Different styles for items before and after a certain (selected or middle) one
Let’s say we have a bunch of radio buttons and labels, with the labels having an index set as a custom property, --i. We want the labels before the selected item to have a green background, the label of the selected item to have a blue background and the rest of the labels to be grey. On the body, we set the index of the currently selected option as another custom property, --k.
- let n = 8; - let k = Math.round((n - 1)*Math.random()); body(style=`--k: ${k}`) - for(let i = 0; i < n; i++) - let id = `r${i}`; input(type='radio' name='r' id=id checked=i===k) label(for=id style=`--i: ${i}`) Option ##{i}
This compiles to the following HTML:
<body style='--k: 1'> <input type='radio' name='r' id='r0'/> <label for='r0' style='--i: 0'>Option #0</label> <input type='radio' name='r' id='r1' checked='checked'/> <label for='r1' style='--i: 1'>Option #1</label> <input type='radio' name='r' id='r2'/> <label for='r2' style='--i: 2'>Option #2</label> <!-- more options --> </body>
We set a few layout and prettifying styles, including a gradient background on the labels that creates three vertical stripes, each occupying a third of the background-size (which, for now, is just the default 100%, the full element width):
$c: #6daa7e, #335f7c, #6a6d6b; body { display: grid; grid-gap: .25em 0; grid-template-columns: repeat(2, max-content); align-items: center; font: 1.25em/ 1.5 ubuntu, trebuchet ms, sans-serif; } label { padding: 0 .25em; background: linear-gradient(90deg, nth($c, 1) 33.333%, nth($c, 2) 0 66.667%, nth($c, 3) 0); color: #fff; cursor: pointer; }
Tumblr media
The result so far.
From the JavaScript, we update the value of --k whenever we select a different option:
addEventListener('change', e => { let _t = e.target; document.body.style.setProperty('--k', +_t.id.replace('r', '')) })
Now comes the interesting part! For our label elements, we compute the sign, --sgn, of the difference between the label index, --i, and the index of the currently selected option, --k. We then use this --sgn value to compute the background-position when the background-size is set to 300% — that is, three times the label’s width because we may have of three possible backgrounds: one for the case when the label is for an option before the selected one, a second for the case when the label is for the selected option, and a third for the case when the label is for an option after the selected one.
--sgn: clamp(-1, var(--i) - var(--k), 1); background: linear-gradient(90deg, nth($c, 1) 33.333%, nth($c, 2) 0 66.667%, nth($c, 3) 0) calc(50%*(1 + var(--sgn)))/ 300%
If --i is smaller than --k (the case of a label for an option before the selected one), then --sgn is -1 and the background-position computes to 50%*(1 + -1) = 50%*0 = 0%, meaning we only see the first vertical stripe (the green one).
If --i is equal --k (the case of the label for the selected option), then --sgn is 0 and the background-position computes to 50%*(1 + 0) = 50%*1 = 50%, so we only see the vertical stripe in the middle (the blue one).
If --i is greater than --k (the case of a label for an option after the selected one), then --sgn is 1 and the background-position computes to 50%*(1 + 1) = 50%*2 = 100%, meaning we only see the last vertical stripe (the grey one).
CodePen Embed Fallback
A more aesthetically appealing example would be the following navigation where the vertical bar is on the side closest to the selected option and, for the selected one, it spreads across the entire element.
This uses a structure that’s similar to that of the previous demo, with radio inputs and labels for the navigation items. The moving “background” is actually an ::after pseudo-element whose translation value depends on the sign, --sgn. The text is a ::before pseudo-element whose position is supposed to be in the middle of the white area, so its translation value also depends on --sgn.
/* relevant styles */ label { --sgn: clamp(-1, var(--k) - var(--i), 1); &::before { transform: translate(calc(var(--sgn)*-.5*#{$pad})) } &::after { transform: translate(calc(var(--sgn)*(100% - #{$pad}))) } }
CodePen Embed Fallback
Let’s now quickly look at a few more demos where computing the sign (and maybe the absolute value as well) comes in handy.
First up, we have a square grid of cells with a radial-gradient whose radius shrinks from covering the entire cell to nothing. This animation has a delay computed as explained in the previous section. What’s new here is that the coordinates of the radial-gradient circle depend on where the cell is positioned with respect to the middle of the grid — that is, on the signs of the differences between the column --i and row --j indices and the middle index, --m.
/* relevant CSS */ $t: 2s; @property --p { syntax: '<length-percentage>'; initial-value: -1px; inherits: false; } .cell { --m: calc(.5*(var(--n) - 1)); --dif-i: calc(var(--m) - var(--i)); --abs-i: max(var(--dif-i), -1*var(--dif-i)); --sgn-i: clamp(-1, var(--dif-i)/.5, 1); --dif-j: calc(var(--m) - var(--j)); --abs-j: max(var(--dif-j), -1*var(--dif-j)); --sgn-j: clamp(-1, var(--dif-j)/.5, 1); background: radial-gradient(circle at calc(50% + 50%*var(--sgn-i)) calc(50% + 50%*var(--sgn-j)), currentcolor var(--p), transparent calc(var(--p) + 1px)) nth($c, 2); animation-delay: calc((.5*(var(--abs-i) + var(--abs-j))/var(--m) - 1)*#{$t}); } @keyframes p { 0% { --p: 100%; } }
Sinking feeling (live demo)
Then we have a double spiral of tiny spheres where both the sphere diameter --d and the radial distance --x that contributes to determining the sphere position depend on the absolute value --abs of the difference between each one’s index, --i, and the middle index, --m. The sign, --sgn, of this difference is used to determine the spiral rotation direction. This depends on where each sphere is with respect to the middle – that is, whether its index ,--i, is smaller or bigger than the middle index, --m.
/* relevant styles */ --m: calc(.5*(var(--p) - 1)); --abs: max(calc(var(--m) - var(--i)), calc(var(--i) - var(--m))); --sgn: clamp(-1, var(--i) - var(--m), 1); --d: calc(3px + var(--abs)/var(--p)*#{$d}); /* sphere diameter */ --a: calc(var(--k)*1turn/var(--n-dot)); /* angle used to determine sphere position */ --x: calc(var(--abs)*2*#{$d}/var(--n-dot)); /* how far from spiral axis */ --z: calc((var(--i) - var(--m))*2*#{$d}/var(--n-dot)); /* position with respect to screen plane */ width: var(--d); height: var(--d); transform: /* change rotation direction by changing x axis direction */ scalex(var(--sgn)) rotate(var(--a)) translate3d(var(--x), 0, var(--z)) /* reverse rotation so the sphere is always seen from the front */ rotate(calc(-1*var(--a))); /* reverse scaling so lighting on sphere looks consistent */ scalex(var(--sgn))
No perspective (live demo)
Finally, we have a grid of non-square boxes with a border. These boxes have a mask created using a conic-gradient with an animated start angle, --ang. Whether these boxes are flipped horizontally or vertically depends on where they are with respect to the middle – that is, on the signs of the differences between the column --i and row --j indices and the middle index, --m. The animation-delay depends on the absolute values of these differences and is computed as explained in the previous section. We also have a gooey filter for a nicer “wormy” look, but we won’t be going into that here.
/* relevant CSS */ $t: 1s; @property --ang { syntax: '<angle>'; initial-value: 0deg; inherits: false; } .box { --m: calc(.5*(var(--n) - 1)); --dif-i: calc(var(--i) - var(--m)); --dif-j: calc(var(--j) - var(--m)); --abs-i: max(var(--dif-i), -1*var(--dif-i)); --abs-j: max(var(--dif-j), -1*var(--dif-j)); --sgn-i: clamp(-1, 2*var(--dif-i), 1); --sgn-j: clamp(-1, 2*var(--dif-j), 1); transform: scale(var(--sgn-i), var(--sgn-j)); mask: repeating-conic-gradient(from var(--ang, 0deg), red 0% 12.5%, transparent 0% 50%); animation: ang $t ease-in-out infinite; animation-delay: calc(((var(--abs-i) + var(--abs-j))/var(--n) - 1)*#{$t}); } @keyframes ang { to { --ang: .5turn; } }
Consumed by worms (live demo)
Time (and not only) formatting
Let’s say we have an element for which we store a number of seconds in a custom property, --val, and we want to display this in a mm:ss format, for example.
We use the floor of the ratio between --val and 60 (the number of seconds in a minute) to get the number of minutes and modulo for the number of seconds past that number of minutes. Then we use a clever little counter trick to display the formatted time in a pseudo-element.
@property --min { syntax: '<integer>'; initial-value: 0; inherits: false; } code { --min: calc(var(--val)/60 - .5); --sec: calc(var(--val) - var(--min)*60); counter-reset: min var(--min) sec var(--sec); &::after { /* so we get the time formatted as 02:09 */ content: counter(min, decimal-leading-zero) ':' counter(sec, decimal-leading-zero); } }
This works in most situations, but we encounter a problem when --val is exactly 0. In this case, 0/60 is 0 and then subtracting .5, we get -.5, which gets rounded to what’s the bigger adjacent integer in absolute value. That is, -1, not 0! This means our result will end up being -01:60, not 00:00!
Fortunately, we have a simple fix and that’s to slightly alter the formula for getting the number of minutes, --min:
--min: max(0, var(--val)/60 - .5);
There are other formatting options too, as illustrated below:
/* shows time formatted as 2:09 */ content: counter(min) ':' counter(sec, decimal-leading-zero); /* shows time formatted as 2m9s */ content: counter(min) 'm' counter(sec) 's';
We can also apply the same technique to format the time as hh:mm:ss (live test).
@property --hrs { syntax: '<integer>'; initial-value: 0; inherits: false; } @property --min { syntax: '<integer>'; initial-value: 0; inherits: false; } code { --hrs: max(0, var(--val)/3600 - .5); --mod: calc(var(--val) - var(--hrs)*3600); --min: max(0, var(--mod)/60 - .5); --sec: calc(var(--mod) - var(--min)*60); counter-reset: hrs var(--hrs) var(--min) sec var(--sec); &::after { /* so we get the time formatted as 00:02:09 */ content: counter(hrs, decimal-leading-zero) ':' counter(min, decimal-leading-zero) ':' counter(sec, decimal-leading-zero); } }
This is a technique I’ve used for styling the output of native range sliders such as the one below.
Tumblr media
Styled range input indicating time (live demo)
Time isn’t the only thing we can use this for. Counter values have to be integer values, which means the modulo trick also comes in handy for displaying decimals, as in the second slider seen below.
Tumblr media
Styled range inputs, one of which has a decimal output (live demo)
A couple more such examples:
Tumblr media
Styled range inputs, one of which has a decimal output (live demo)
Tumblr media
Styled range inputs, one of which has a decimal output (live demo)
Even more use cases
Let’s say we have a volume slider with an icon at each end. Depending on the direction we move the slider’s thumb in, one of the two icons gets highlighted. This is possible by getting the absolute value, --abs, of the difference between each icon’s sign, --sgn-ico (-1 for the one before the slider, and 1 for the one after the slider), and the sign of the difference, --sgn-dir, between the slider’s current value, --val, and its previous value, --prv. If this is 0, then we’re moving in the direction of the current icon so we set its opacity to 1. Otherwise, we’re moving away from the current icon, so we keep its opacity at .15.
This means that, whenever the range input’s value changes, not only do we need to update its current value, --val, on its parent, but we need to update its previous value, which is another custom property, --prv, on the same parent wrapper:
addEventListener('input', e => { let _t = e.target, _p = _t.parentNode; _p.style.setProperty('--prv', +_p.style.getPropertyValue('--val')) _p.style.setProperty('--val', +_t.value) })
The sign of their difference is the sign of the direction, --sgn-dir, we’re going in and the current icon is highlighted if its sign, --sgn-ico, and the sign of the direction we’re going in, --sgn-dir, coincide. That is, if the absolute value, --abs, of their difference is 0 and, at the same time, the parent wrapper is selected (it’s either being hovered or the range input in it has focus).
[role='group'] { --dir: calc(var(--val) - var(--prv)); --sgn-dir: clamp(-1, var(--dir), 1); --sel: 0; /* is the slider focused or hovered? Yes 1/ No 0 */ &:hover, &:focus-within { --sel: 1; } } .ico { --abs: max(var(--sgn-dir) - var(--sgn-ico), var(--sgn-ico) - var(--sgn-dir)); --hlg: calc(var(--sel)*(1 - min(1, var(--abs)))); /* highlight current icon? Yes 1/ No 0 */ opacity: calc(1 - .85*(1 - var(--hlg))); }
CodePen Embed Fallback
Another use case is making property values of items on a grid depend on the parity of the sum of horizontal --abs-i and vertical --abs-j distances from the middle, --m. For example, let’s say we do this for the background-color:
@property --floor { syntax: '<integer>'; initial-value: 0; inherits: false; } .cell { --m: calc(.5*(var(--n) - 1)); --abs-i: max(var(--m) - var(--i), var(--i) - var(--m)); --abs-j: max(var(--m) - var(--j), var(--j) - var(--m)); --sum: calc(var(--abs-i) + var(--abs-j)); --floor: max(0, var(--sum)/2 - .5); --mod: calc(var(--sum) - var(--floor)*2); background: hsl(calc(90 + var(--mod)*180), 50%, 65%); }
Tumblr media
Background depending on parity of sum of horizontal and vertical distances to the middle (live demo)
We can spice things up by using the modulo 2 of the floor of the sum divided by 2:
@property --floor { syntax: '<integer>'; initial-value: 0; inherits: false; } @property --int { syntax: '<integer>'; initial-value: 0; inherits: false; } .cell { --m: calc(.5*(var(--n) - 1)); --abs-i: max(var(--m) - var(--i), var(--i) - var(--m)); --abs-j: max(var(--m) - var(--j), var(--j) - var(--m)); --sum: calc(var(--abs-i) + var(--abs-j)); --floor: max(0, var(--sum)/2 - .5); --int: max(0, var(--floor)/2 - .5); --mod: calc(var(--floor) - var(--int)*2); background: hsl(calc(90 + var(--mod)*180), 50%, 65%); }
Tumblr media
A more interesting variation of the previous demo (live demo)
We could also make both the direction of a rotation and that of a conic-gradient() depend on the same parity of the sum, --sum, of horizontal --abs-i and vertical --abs-j distances from the middle, --m. This is achieved by horizontally flipping the element if the sum, --sum, is even. In the example below, the rotation and size are also animated via Houdini (they both depend on a custom property, --f, which we register and then animate from 0 to 1), and so are the worm hue, --hue, and the conic-gradient() mask, both animations having a delay computed exactly as in previous examples.
@property --floor { syntax: '<integer>'; initial-value: 0; inherits: false; } .🐛 { --m: calc(.5*(var(--n) - 1)); --abs-i: max(var(--m) - var(--i), var(--i) - var(--m)); --abs-j: max(var(--m) - var(--j), var(--j) - var(--m)); --sum: calc(var(--abs-i) + var(--abs-j)); --floor: calc(var(--sum)/2 - .5); --mod: calc(var(--sum) - var(--floor)*2); --sgn: calc(2*var(--mod) - 1); /* -1 if --mod is 0; 1 id --mod is 1 */ transform: scalex(var(--sgn)) scale(var(--f)) rotate(calc(var(--f)*180deg)); --hue: calc(var(--sgn)*var(--f)*360); }
Grid wave: triangular rainbow worms (live demo).
Finally, another big use case for the techniques explained so far is shading not just convex, but also concave animated 3D shapes using absolutely no JavaScript! This is one topic that’s absolutely massive on its own and explaining everything would take an article as long as this one, so I won’t be going into it at all here. But I have made a few videos where I code a couple of such basic pure CSS 3D shapes (including a wooden star and a differently shaped metallic one) from scratch and you can, of course, also check out the CSS for the following example on CodePen.
Musical toy (live demo)
The post Using Absolute Value, Sign, Rounding and Modulo in CSS Today appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.
Using Absolute Value, Sign, Rounding and Modulo in CSS Today published first on https://deskbysnafu.tumblr.com/
0 notes
holytheoristtastemaker · 5 years ago
Link
In this post, we'll see what atomic CSS is, how it relates to functional / utility-first CSS like TailwindCSS, and that big players are adopting it in their modern React codebases. As I'm not a expert of this subject, don't expect a deep dive about the pros and cons. I just hope you get an idea about what it's about. Note: Atomic CSS is not really related to Atomic Design.
What is atomic CSS?
You may have heard of various CSS methodologies like BEM, OOCSS...
<button class="button button--state-danger"> Danger button </button>
These days, people really like Tailwind CSS and its utility-first concept. This is close to Functional CSS and Tachyon.
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Button </button>
With a stylesheet of a bunch of utility classes, you can go a long way. Atomic CSS is like an extreme version of utility-first CSS: all CSS classes have a single, unique CSS rule. Atomic CSS was first used by Thierry Koblentz (Yahoo!), in Challenging CSS Best Practices in 2013.
/* Atomic CSS */ .bw-2x { border-width: 2px; } .bss { border-style: solid; } .sans { font-style: sans-serif; } .p-1x { padding: 10px; } /* Not atomic, because the class contains 2 rules */ .p-1x-sans { padding: 10px; font-style: sans-serif; }
With utility/atomic CSS, we acknowledge it's ok to couple the structure and presentation layers: when we need to change the button color, we modify the HTML, not the CSS. This tight coupling is also acknowledged in modern CSS-in-JS React codebases, but it seems the CSS world figured out first that the "separation of concern" of the web didn't feel right. Specificity is also less a problem, as we use simple class selectors. We are now styling via the markup, which has several interesting properties:
the stylesheet grows less as we add new features
we can move the markup around, and the styles are moved at the same time
we can remove features, and be sure that we remove the related styling at the same time
For sure, the html is a bit more bloated. This can be a concern for server rendered web apps, but the high redundancy in class names compress well with gzip, in the same way it worked well for duplicated css rules previously found in your CSS files. You don't need to use utility/atomic CSS for every cases, just the most common styling patterns. Once your utility/atomic CSS is ready, it will not change or grow much. It's possible to cache it more aggressively (you can append it to vendor.css for example, and expect it to not invalidate across app redeploys). It is also quite portable, and you can use it in other applications.
Limits of utility/atomic CSS
Utility/atomic CSS looks interesting, but they come with a few challenges as well. People usually write utility/atomic CSS by hand, carefully crafting naming conventions. It can be hard to ensure the convention is easy to use, consistent, and not bloated over time. Can multiple persons work on this CSS and keep it consistent? Is it subject to the bus factor? You also need to work on a good utility/atomic stylesheet up-front, before being able to iterate on features that will use it. If the utility/atomic CSS is made by someone else, you will have to learn the class naming conventions first (even if you know everything about CSS). This convention is opiniated, and it's possible that you don't like it. Sometimes, you need some extra CSS that is not provided by your utility/atomic CSS. There's no unique way to provide the remaining one-off styles.
Tailwind to the rescue
The approach of Tailwind is very convenient, and solves some of these problems. It does not really provide a unique utility CSS file for all websites. Instead, it only provides a shared scope and naming conventions. From a configuration file, it allows you to generate your own custom utility CSS. Knowledge of Tailwind is portable to other applications, even if they don't use exactly the same class names. It reminds me a bit of the "Learn once, write anywhere" philosophy of React. I've seen people reporting that Tailwind classes cover something between 90% or 95% of their needs. It seems the scope is large enough, and we don't often need to use one-off style. At this point you might wonder why use atomic CSS instead of Tailwind?. What would you gain in enforcing the atomic CSS rule of 1 rule, 1 class? You would end up with a larger html markup, and a less convenient naming convention? Tailwind already has many atomic classes anyway. So, should we abandon the idea of atomic CSS, and simply use Tailwind? Tailwind is a great solution, but there are still a few problems that remain unsolved:
the need to learn an opiniated naming convention
CSS rules insertion order still matters
can unused rules be easily removed?
what do we do with the remaining one-off styles?
Handwritten atomic CSS might not be the most convenient compared to Tailwind.
Comparison with CSS-in-JS
There's a relationship with CSS-in-JS, and utility/atomic CSS. Both approaches advocate for styling from the markup, somehow trying to emulate performant inline styles, which gives them many similar properties (like the ability to move things around with confidence). Christopher Chedeau greatly helped spread the idea of CSS-in-JS in the React ecosystem. In multiple talks, he explains the problems of CSS:
Tumblr media
Utility/atomic CSS solve some of these problems too, but definitively not all (particularly, the non-deterministic resolution of styles). If they share similarities, can't we use them both together?
Enter atomic CSS-in-JS
Atomic CSS-in-JS can be seen as "automatic atomic CSS":
You don't need to create a class name convention anymore
Common and one-off styles are treated the same way
Ability extract the critical CSS of a page, and do code-splitting
An opportunity to fix the CSS rules insertion order issues in JS
I'm not aware about all CSS-in-JS libraries out there currently supporting atomic CSS. Supporting it is actually an implementation detail of the CSS-in-JS library. Support might come and go, or can even be made optional. I will highlight 2 particular solutions, that recently lead to 2 large-scale atomic CSS-in-JS deployments, using 2 talks as sources:
React-Native-Web at Twitter (more details in Nicolas Gallagher's talk)
Stylex at Facebook (more details in Frank Yan's talk)
See also: Styletron, Fela, cxs
React-Native-Web
React-Native-Web is a very interesting library: it permits to render React-Native primitives on the web. We are not really talking about cross-platform mobile/web development here (watch the talks for more details). As a web developer, you just need to understand that React-Native-Web is a regular CSS-in-JS library, that comes with a small set of primitive React components. Wherever you see View, you can replace it in your mind with div, and you are good to go. React-Native-Web has been created by Nicolas Gallagher, working on Twitter mobile. They progressively deployed it to mobile, not sure when exactly but probably around 2017/2018. Since then, it has been used by other companies (Major League Soccer, Flipkart, Uber, The Times...), but the most significant deployment has been the new 2019 Twitter desktop app by a team lead by Paul Armstrong.
Tumblr media
Stylex
Stylex is a new CSS-in-JS library developed at Facebook for the 2020 Facebook rewrite (currently in beta). It seems they plan to open-source it some day, possibly under a different name. It's worth mentioning that Nicolas Gallagher, the author of React-Native-Web, was hired by Facebook 2 years ago. It's not a big surprise to see some of its concept being reused by Facebook. Unlike React-Native-Web, Stylex does not seem focused on cross-platform development. All the infos I have are from the talk :) We'll have to wait for more details.
Scalability
As expected with atomic CSS, both Twitter and Facebook have seen a massive reduction of their CSS, as it now follows a logarithmic curve. There's an initial price to pay for simple apps though.
Tumblr media Tumblr media
Facebook shared concrete numbers:
Their old site was 413Kb of CSS just for the landing page
Their new site is 74Kb for the whole site, including the dark mode
Tumblr media
Source and output
The 2 libraries looks quite similar here, but it's hard to say, considering we don't know much about Stylex. It's worth highlighting React-Native-Web will expand the CSS shortand syntaxes like margin: 0.
Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media
Production inspection
Let's look at what the markup looks like on Twitter:
Tumblr media
Now, let's look at the new Facebook:
Tumblr media
Many people will probably be horrified when seeing this, but it actually works, and remains accessible. It might be a bit harder to navigate styles in the Chrome inspector, but devtools can help:
Tumblr media
CSS rules order
Unlike handwritten utility/atomic CSS, the JS libs are able to make the styling not dependent of the CSS rules insertion order. As you may know, in case of conflicting rules, it's not the last class of a class attribute that wins, but the rule that is inserted last in the stylesheet. Specificity issues are solved by only using simple class-based selectors.
Tumblr media Tumblr media
In practice, these libraries avoid outputting classes with conflicting rules on the same element. They ensure that the last style declared in the markup always wins. The "overridden classes" are filtered, and don't even make it to the DOM.
const styles = pseudoLib.create({ red: {color: "red"}, blue: {color: "blue"}, }); // That div only will have a single atomic class (not 2!), for the blue color <div style={[styles.red, styles.blue]}> Always blue! </div> // That div only will have a single atomic class (not 2!), for the red color <div style={[styles.blue, styles.red]}> Always red! </div>
Note: This predictable behavior is only possible thanks to using the most strict atomic CSS. If a class had multiple rules, and only one of them was overridden, the CSS-in-JS library wouldn't be able to filter that class without removing the non-overridden rules as well. If a class had a single shorthand rule like margin: 0, and the override was marginTop: 10, it's the same problem. The shorthand syntax like margin: 0 is expanded to 4 distinct classes, and the library is able to filter overridden classes that should not appear in the DOM with more granularity.
You still prefer Tailwind?
Once you know all the Tailwind naming conventions, you can code an UI very fast. It might feel less productive to go back to writing every CSS rule by hand, like you do in CSS-in-JS. Nothing prevents your for building your own abstractions on top of an atomic CSS-in-JS framework. Styled-system might be able to run some of the CSS-in-JS libraries supporting atomic CSS. It's even possible to reuse naming conventions for Tailwind in JS, if you feel you are productive with it. Let's take some Tailwind code:
<div className="absolute inset-0 p-4 bg-blue-500" />
Now, let's take a random solution (react-native-web-tailwindcss) I just found on google:
import {t} from 'react-native-tailwindcss'; <View style={[t.absolute, t.inset0, t.p4, t.bgBlue500]} />
In term of productivity, this is not very different. And you could avoid typos with TypeScript.
Conclusion
To me, using Atomic CSS, CSS-in-JS, and Tailwind all at the same time makes sense. That's almost everything I have to say about atomic CSS-in-JS. I have never used atomic CSS, atomic CSS-in-JS, or Tailwind in any large production deployment. I'm probably wrong on some parts, feel free to correct me on Twitter. I think atomic CSS-in-JS is a trend to watch in the React ecosystem, and I hope you learned something useful with this post. As I've not been able to find any article about atomic CSS-in-JS, I wrote this mostly for myself. I want a resource to link to when I mention atomic CSS-in-JS in upcoming blog posts (I plan to write more articles about React-Native-Web and cross-platform, stay tuned). Thank you for reading.
0 notes
siliconwebx · 6 years ago
Text
Edge Goes Chromium: What Does it Mean for Front-End Developers?
In December 2018, Microsoft announced that Edge would adopt Chromium, the open source project that powers Google Chrome. Many within the industry reacted with sadness at the loss of browser diversity. Personally, I was jubilant. An official release date has yet to be announced, but it will be at some point this year. With its release, a whole host of HTML, JavaScript and CSS features will have achieved full cross-browser support.
The preview build is now available for Windows, and coming soon for Mac.
📣 Calling all web devs and tinkerers! 📣
The first preview builds of the next version of #MicrosoftEdge are ready for you – try it out now! https://t.co/I531hfmD3G pic.twitter.com/Tvh6OGGouO
— Microsoft Edge Dev (@MSEdgeDev) April 8, 2019
Not so long ago, I penned an article titled "The Long Slow Death of Internet Explorer." Some of us are lucky enough have abandoned that browser already. But it wasn’t the only thing holding us back. Internet Explorer was the browser we all hated and Edge was meant to be its much-improved replacement. Unfortunately, Edge itself was quite the laggard. EdgeHTML is a fork of Trident, the engine that powered Internet Explorer. Microsoft significantly under-invested in Edge. The apple didn’t fall far from the tree. Edge’s User Voice website was a nice idea, allowing developers to vote for which features they wanted to be implemented. Unfortunately, as Dave Rupert put it, voting on the site was "like throwing coins in a wishing well." The most requested features were left unimplemented for years.
There are a lot of features that pre-Chromium Edge doesn’t currently support but are available in other modern browsers and, once they’ve made the switch, we’ll be able to use them. Many of them can’t be polyfilled or worked around, so this release is a big deal.
caniuse.com comparing the final non-Chromium version of Edge to the other popular modern browser
Features we can look forward to using
So just what are those features, exactly? Let’s outline them right here and start to get excited about all the new things we’ll be able to do.
Custom Elements and Shadow DOM
Together, custom elements and shadow DOM allow developers to define custom, reusable and encapsulated components. A lot of people were asking for this one. People have been voting for its implementation since 2014, and we’re finally getting it.
Tumblr media
HTML details and summary elements
The <details> and <summary> elements are part of HTML5 and have been supported since 2011 in Chrome. Used together, the elements generate a simple widget to show and hide content. While it is trivial to implement something similar using JavaScript, the <details> and <summary> elements work even when JavaScript is disabled or has failed to load.
See the Pen details/summary by CSS GRID (@cssgrid) on CodePen.
Javascript Font Loading API
This one means a lot to some people. All modern browsers now support the CSS font-display property. However, you still might want to load your fonts with JavaScript. Font-loading monomaniac Zach Leatherman has an explainer of why you might want to load fonts with JavaScript even though we now have broad support for font-display. Ditching polyfills for this API is important because this JavaScript is, according to Zach:
[...] usually inlined in the critical path. The time spent parsing and executing polyfill JavaScript is essentially wasted on browsers that support the native CSS Font Loading API."
In an article from 2018, Zach lamented:
[...] browser-provided CSS Font Loading API has pretty broad support and has been around for a long time but is confoundedly still missing from all available versions of Microsoft Edge."
No longer!
JavaScript flat and flatMap
Most easily explained with a code snippet, flat() is useful when you have an array nested inside another array.
const things = ['thing1', 'thing2', ['thing3', ['thing4']]] const flattenedThings = things.flat(2); // Returns ['thing1', 'thing2', 'thing3', 'thing4']
As its name suggests, flatMap() is equivalent to using both the map() method and flat().
These methods are also supported in Node 11. 🎉
JavaScript TextEncoder and TextDecoder
TextEncoder and TextDecoder are part of the encoding spec. They look to be useful when working with streams.
JavaScript Object rest and object spread
These are just like rest and spread properties for arrays.
const obj1 = { a: 100, b: 2000 } const obj2 = { c: 11000, d: 220 } const combinedObj = {...obj1, ...obj2} // {a: 100, b: 2000, c: 11000, d: 220}
JavaScript modules: dynamic import
Using a function-like syntax, dynamic imports allow you to lazy-load ES modules when a user needs them.
button.addEventListener("click", function() { import("./myModule.js").then(module => module.default()); });
CSS background-blend-mode property
background-blend-mode brings Photoshop style image manipulation to the web.
CSS prefers-reduced-motion media query
I can’t help feeling that not making people feel sick should be the default of a website, particularly as not all users will be aware that this setting exists. As animation on the web becomes more common, it’s important to recognize that animation can cause causes dizziness, nausea and headaches for some users.
Tumblr media
CSS font-display property
font-display has been well-covered on CSS-Tricks before. It's a way to control the perceived performance of font loading.
CSS caret-color property
Admittedly a rather trivial feature, and one that could have safely and easily been used as progressive enhancement. It lets you style the blinking cursor in text input fields.
8-digit hex color notation
It’s nice to have consistency in a codebase. This includes sticking to either the RGB, hexadecimal or HSL color format. If your preferred format is hex, then you had a problem because it required a switch to rgba() any time you needed to define transparency. Hex can now include an alpha (transparency) value. For example, #ffffff80 is equivalent to rgba(255, 255, 255, .5). Arguably, it’s not the most intuitive color format and has no actual benefit over rgba().
Intrinsic sizing
I’ve not seen as much hype or excitement for intrinsic sizing as some other new CSS features, but it’s the one I’m personally hankering for the most. Intrinsic sizing determines sizes based on the content of an element and introduces three new keywords into CSS: min-content, max-content and fit-content(). These keywords can be used most places that you would usually use a length, like height, width, min-width, max-width, min-height, max-height, grid-template-rows, grid-template-columns, and flex-basis.
CSS text-orientation property
Used in conjunction with the writing-mode property, text-orientation, specifies the orientation of text, as you might expect.
See the Pen text-orientation: upright by CSS GRID (@cssgrid) on CodePen.
CSS :placeholder-shown pseudo-element
placeholder-shown was even available in Internet Explorer, yet somehow never made it into Edge... until now. UX research shows that placeholder text should generally be avoided. However, if you are using placeholder text, this is a handy way to apply styles conditionally based on whether the user has entered any text into the input.
CSS place-content property
place-content is shorthand for setting both both the align-content and justify-content.
See the Pen place-content by CSS GRID (@cssgrid) on CodePen.
CSS will-change property
The will-change property can be used as a performance optimization, informing the browser ahead of time that an element will change. Pre-Chromium Edge was actually good at handling animations performantly without the need for this property, but it will now have full cross-browser support.
CSS all property
all is a shorthand for setting all CSS properties at once.
For example, setting button { all: unset; } is equivalent to:
button { background: none; border: none; color: inherit; font: inherit; outline: none; padding: 0; }
Sadly, though, the revert keyword still hasn’t been implemented anywhere other than Safari, which somewhat limits the mileage we can get out of the all property.
CSS Shapes and Clip Path
Traditionally, the web has been rectangle-centric. It has a box model, after all. While we no longer need floats for layout, we can use them creatively for wrapping text around images and shapes with the shape-outside property. This can be combined with the clip-path property, which brings the ability to display an image inside a shape.
Tumblr media
Clippy is an online clip-path editor
CSS :focus-within pseudo-class
If you want to apply special styles to an entire form when any one of its inputs are in focus, then :focus-within is the selector for you.
CSS contents keyword
This is pretty much essential if you’re working with CSS grid. This had been marked as "not planned" by Edge, despite 3,920 votes from developers.
Tumblr media
For both flexbox and grid, only direct children become flex items or grid items, respectively. Anything that is nested deeper cannot be placed using flex or grid-positioning. In the words of the spec, when display: contents is applied to a parent element, "the element must be treated as if it had been replaced in the element tree by its contents," allowing them to be laid out with a grid or with flexbox. Chris goes into a more thorough explanation that’s worth checking out.
There are, unfortunately, still some bugs with other browser implementations that affect accessibility.
The future holds so much more promise
We’ve only looked at features that will be supported by all modern browsers when Edge makes the move to Chromium. That said, the death of legacy Edge also makes a lot of other features feel a lot closer. Edge was the only browser dragging its feet on the Web Animation API and that showed no interest in any part of the Houdini specs, for example.
Tumblr media
Credit: https://ishoudinireadyyet.com
The impact on browser testing
Tumblr media
Testing in BrowserStack (left) and various browser apps on my iPhone (right)
Of course, the other huge plus for web developers is less testing. A lot of neglected Edge during cross-browser testing, so Edge users were more likely to have a broken experience. This was the main reason Microsoft decided to switch to Chromium. If your site is bug-free in one Chromium browser, then it’s probably fine in all of them. In the words of the Edge team, Chromium will provide "better web compatibility for our customers and less-fragmentation of the web for all web developers." The large variety of devices and browsers makes browser testing one of the least enjoyable tasks that we’re responsible for as front-end developers. Edge will now be available for macOS users which is great for the many of us who work on a Mac. A subscription to BrowserStack will now be slightly less necessary.
Do we lose anything?
To my knowledge, the only feature that was supported everywhere except Chrome is SVG color fonts, which will no longer work in the Edge browser. Other color font formats (COLR, SBIX, CBDT/CBLC) will continue to work though.
Uh, @GoogleChrome Are you planning to support #OpenTypeSVG soon? Supported in Safari (12+), Firefox (26+) even EdgeHTML (38+) Photoshop, Illustrator - but not Chrome /cc @colorfontswtf pic.twitter.com/tgwJ3AqHm2
— Chris Lilley (@svgeesus) February 15, 2019
What about other browsers?
Admittedly, Edge wasn’t the last subpar browser. All the features in this article are unsupported in Internet Explorer, and always will be. If you have users in Russia, you’ll need to support Yandex. If you have users in Africa, you’ll need to support Opera Mini. If you have users in China, then UC and QQ will be important to test against. If you don’t have these regional considerations, there’s never been a better time to ditch support for Internet Explorer and embrace the features the modern web has to offer. Plenty of PC users have stuck with Internet Explorer purely out of habit. Hopefully, a revamped Edge will be enough to tempt them away. An official Microsoft blog entry titled "The perils of using Internet Explorer as your default browser" concluded that, "Internet Explorer is a compatibility solution...developers by and large just aren’t testing for Internet Explorer these days." For its remaining users, the majority of the web must look increasingly broken. It’s time to let it die.
Is Google a megalomaniac?
Life is about to get easier for web developers, yet the response to the Microsoft’s announcement was far from positive. Mozilla, for one, had a stridently pessimistic response, which accused Microsoft of "officially giving up on an independent shared platform for the internet." The statement described Google as having "almost complete control of the infrastructure of our online lives" and a "monopolistic hold on unique assets." It concluded that "ceding control of fundamental online infrastructure to a single company is terrible."
Tumblr media
Many have harked back to the days of IE6, the last time a browser achieved such an overwhelming market share. Internet Explorer, having won the browser war, gave in to total stagnation. Chrome, by contrast, ceaselessly pushes new features. Google participates actively with the web standards bodies the W3C and the WHATWG. Arguably though, it has an oversized influence in these bodies and the power to dictate the future shape of the web. Google Developer Relations does have a tendency to hype features that have shipped only in Chrome.
From competition to collaboration
Rather than being the new IE, Edge can help innovate the web forward. While it fell behind in many areas, it did lead the way for CSS grid, CSS exclusions, CSS regions and the new HTML imports spec. In a radical departure from historical behavior, Microsoft have become one of the world’s largest supporters of open source projects. That means all major browsers are now open source. Microsoft have stated that they intend to become a significant contributor to Chromium — in fact, they’ve already racked up over 300 merges. This will help Edge users, but will also benefit users of Chrome, Opera, Brave, and other Chromium-based browsers.
The post Edge Goes Chromium: What Does it Mean for Front-End Developers? appeared first on CSS-Tricks.
😉SiliconWebX | 🌐CSS-Tricks
0 notes
mbaljeetsingh · 5 years ago
Text
Practice GraphQL Queries With the State of JavaScript API
Learning how to build GraphQL APIs can be quite challenging. But you can learn how to use GraphQL APIs in 10 minutes! And it so happens I've got the perfect API for that: the brand new, fresh-of-the-VS-Code State of JavaScript GraphQL API.
The State of JavaScript survey is an annual survey of the JavaScript landscape. We've been doing it for four years now, and the most recent edition reached over 20,000 developers.
We've always relied on Gatsby to build our showcase site, but until this year, we were feeding our data to Gatsby in the form of static YAML files generated through some kind of arcane magic known to mere mortals as "ElasticSearch."
But since Gatsby poops out all the data sources it eats as GraphQL anyway, we though we might as well skip the middleman and feed it GraphQL directly! Yes I know, this metaphor is getting grosser by the second and I already regret it. My point is: we built an internal GraphQL API for our data, and now we're making it available to everybody so that you too can easily exploit out dataset!
"But wait," you say. "I've spent all my life studying the blade which has left me no time to learn GraphQL!" Not to worry: that's where this article comes in.
What is GraphQL?
At its core, GraphQL is a syntax that lets you specify what data you want to receive from an API. Note that I said API, and not database. Unlike SQL, a GraphQL query does not go to your database directly but to your GraphQL API endpoint which, in turn, can connect to a database or any other data source.
The big advantage of GraphQL over older paradigms like REST is that it lets you ask for what you want. For example:
query { user(id: "foo123") {     name   } }
Would get you a user object with a single name field. Also need the email? Just do:
query {   user(id: "foo123") {     name     email   } }
As you can see, the user field in this example supports an id argument. And now we come to the coolest feature of GraphQL, nesting:
query {   user(id: "foo123") {     name     email posts { title body } } }
Here, we're saying that we want to find the user's posts, and load their title and body. The nice thing about GraphQL is that our API layer can do the work of figuring out how to fetch that extra information in that specific format since we're not talking to the database directly, even if it's not stored in a nested format inside our actual database.
Sebastian Scholl does a wonderful job explaining GraphQL as if you were meeting it for the first time at a cocktail mixer.
Introducing GraphiQL
Building our first query with GraphiQL, the IDE for GraphQL
GraphiQL (note the "i" in there) is the most common GraphQL IDE out there, and it's the tool we'll use to explore the State of JavaScript API. You can launch it right now at graphiql.stateofjs.com and it'll automatically connect to our endpoint (which is api.stateofjs.com/graphql). The UI consists of three main elements: the Explorer panel, the Query Builder and the Results panels. We'll later add the Docs panels to that but let's keep it simple for now.
The Explorer tab is part of a turbo-boosted version of GraphiQL developed and maintained by OneGraph. Much thanks to them for helping us integrate it. Be sure to check out their example repo if you want to deploy your own GraphiQL instance.
Don't worry, I'm not going to make you write any code just yet. Instead, let's start from an existing GraphQL query, such as the one corresponding to developer experience with React over the past four years.
Remember how I said we were using GraphQL internally to build our site? Not only are we exposing the API, we're also exposing the queries themselves. Click the little "Export" button, copy the query in the "GraphQL" tab, paste it inside GraphiQL's query builder window, and click the "Play" button.
Source URL
The GraphQL tab in the modal that triggers when clicking Export.
If everything went according to plan, you should see your data appear in the Results panel. Let's take a moment to analyze the query.
query react_experienceQuery { survey(survey: js) { tool(id: react) { id entity { homepage name github { url } } experience { allYears { year total completion { count percentage } awarenessInterestSatisfaction { awareness interest satisfaction } buckets { id count percentage } } } } } }
First comes the query keyword which defines the start of our GraphQL query, along with the query's name, react_experienceQuery. Query names are optional in GraphQL, but can be useful for debugging purposes.
We then have our first field, survey, which takes a survey argument. (We also have a State of CSS survey so we needed to specify the survey in question.) We then have a tool field which takes an id argument. And everything after that is related to the API results for that specific tool. entity gives you information on the specific tool selected (e.g. React) while experience contains the actual statistical data.
Now, rather than keep going through all those fields here, I'm going to teach you a little trick: Command + click (or Control + click) any of those fields inside GraphiQL, and it will bring up the Docs panel. Congrats, you've just witnessed another one of GraphQL's nifty tricks, self-documentation! You can write documentation directly into your API definition and GraphiQL will in turn make it available to end users.
Changing variables
Let's tweak things a bit: in the Query Builder, replace "react" with "vuejs" and you should notice another cool GraphQL thing: auto-completion. This is quite helpful to avoid making mistakes or to save time! Press "Play" again and you'll get the same data, but for Vue this time.
Using the Explorer
We'll now unlock one more GraphQL power tool: the Explorer. The Explorer is basically a tree of your entire API that not only lets you visualize its structure, but also build queries without writing a single line of code! So, let's try recreating our React query using the explorer this time.
First, let's open a new browser tab and load graphiql.stateofjs.com in it to start fresh. Click the survey node in the Explorer, and under it the tool node, click "Play." The tool's id field should be automatically added to the results and — by the way — this is a good time to change the default argument value ("typescript") to "react."
Next, let's keep drilling down. If you add entity without any subfields, you should see a little squiggly red line underneath it letting you know you need to also specify at least one or more subfields. So, let's add id, name and homepage at a minimum. Another useful trick: you can automatically tell GraphiQL to add all of a field's subfields by option+control-clicking it in the Explorer.
Next up is experience. Keep adding fields and subfields until you get something that approaches the query you initially copied from the State of JavaScript site. Any item you select is instantly reflected inside the Query Builder panel. There you go, you just wrote your first GraphQL query!
Filtering data
You might have noticed a purple filters item under experience. This is actually they key reason why you'd want to use our GraphQL API as opposed to simply browsing our site: any aggregation provided by the API can be filtered by a number of factors, such as the respondent's gender, company size, salary, or country.
Expand filters and select companySize and then eq and range_more_than_1000. You've just calculated React's popularity among large companies! Select range_1 instead and you can now compare it with the same datapoint among freelancers and independent developers.
It's important to note that GraphQL only defines very low-level primitives, such as fields and arguments, so these eq, in, nin, etc., filters are not part of GraphQL itself, but simply arguments we've defined ourselves when setting up the API. This can be a lot of work at first, but it does give you total control over how clients can query your API.
Conclusion
Hopefully you've seen that querying a GraphQL API isn't that big a deal, especially with awesome tools like GraphiQL to help you do it. Now sure, actually integrating GraphQL data into a real-world app is another matter, but this is mostly due to the complexity of handling data transfers between client and server. The GraphQL part itself is actually quite easy!
Whether you're hoping to get started with GraphQL or just learn enough to query our data and come up with some amazing new insights, I hope this guide will have proven useful!
And if you're interested in taking part in our next survey (which should be the State of CSS 2020) then be sure to sign up for our mailing list so you can be notified when we launch it.
State of JavaScript API Reference
You can find more info about the API (including links to the actual endpoint and the GitHub repo) at api.stateofjs.com.
Here's a quick glossary of the terms used inside the State of JS API.
Top-Level Fields
Demographics: Regroups all demographics info such as gender, company size, salary, etc.
Entity: Gives access to more info about a specific "entity" (library, framework, programming language, etc.).
Feature: Usage data for a specific JavaScript or CSS feature.
Features: Same, but across a range of features.
Matrices: Gives access to the data used to populate our cross-referential heatmaps.
Opinion: Opinion data for a specific question (e.g. "Do you think JavaScript is moving in the right direction?").
OtherTools: Data for the "other tools" section (text editors, browsers, bundlers, etc.).
Resources: Data for the "resources" section (sites, blogs, podcasts, etc.).
Tool: Experience data for a specific tool (library, framework, etc.).
Tools: Same, but across a range of tools.
ToolsRankings: Rankings (awareness, interest, satisfaction) across a range of tools.
Common Fields
Completion: Which proportion of survey respondents answered any given question.
Buckets: The array containing the actual data.
Year/allYears: Whether to get the data for a specific survey year; or an array containing all years.
The post Practice GraphQL Queries With the State of JavaScript API appeared first on CSS-Tricks.
via CSS-Tricks https://ift.tt/2S05TOQ
0 notes
douchebagbrainwaves · 5 years ago
Text
WORK ETHIC AND PILOT
What were we going to do in the design of the program benefits from evolution. The higher-level abstractions, which you can get started, as we did, using a desktop computer, you end up with a statistical sort of correctness. I've said some harsh things in this essay, but really the thesis is an optimistic one—that if you own the channel, there's a lot they can do to keep the two forces balanced. To be attractive to hackers, a language designer would do well to act as if drugs were themselves the cause of the problem. The syntax of the language is brief to a fault. Get a version 1. Where I grew up, it felt as if there was a change in the social conventions and perhaps the laws governing the way big companies worked. Even for someone in the eightieth percentile assuming, as everyone knows, should generate fast code. What happened? I think, if one looked, that this would be impossible, that the smart kids are unpopular because they're distracted. When you release software gradually you get far fewer bugs to start with. You'll pay more for Internet services than you do for the hardware, just as there was in the early 1970s, before C, MIT's dialect of Lisp, called MacLisp, was one of the most important changes in this new world as they did the world of desktop applications.
What makes a language good for throwaway programs? In the best case you do it like a pilot scanning the instrument panel, not like a detective trying to unravel some mystery. But it could be any other way, as long as no one is forced to use it from examples in a couple minutes. Introducing change is like pulling off a bandage: the pain is a memory almost as soon as it has a quantum of utility, and then see what they do with it.1 History suggests that, all other things being equal, no one is forced to use it. They do not generally get to the end of it they had built a real, working store. The customers were delighted. But you can. Richard and Jonathan Rees have done a lot of i/o fast, because server-based application will be a good long period of cheerful chaos, just as we know in the abstract, that kids are monstrously cruel to one another, just as there was in the early days of microcomputers.
A typical desktop software company, this would have been the part where we were working hard, but it may be more than a local effect. But even so I'd advise startups to pull a Meraki initially if they can avoid it. Given that you can start a startup. A typical desktop software company, this would have been, we didn't have, so I'd spend a couple hours implementing it and then resume building the site. Some we helped with strategy questions, like what to patent, and what it means is to have a deft touch. If you can find and fix most bugs as soon as it has a quantum of utility, and then buy it, as two separate steps. And vice versa: you'll sell more of something when it's easy to buy.
Europeans didn't introduce formal civil service exams took years, as prep school does today. School is a strange, artificial thing, half sterile and half feral. Only 13 of these were in product development. Most were emerging from twenty or so years of being used only by a small number of early adopters. With purely Web-based applications. Think of some successful startups. Perhaps a few will have the energy to try to baby the user with long-winded expressions that are meant to resemble English. The last ingredient a popular language, you either have to supply more than a language, or you have to resort to focus groups, you'll wish you could go over to your users' homes and offices and watch them use your stuff like you did when there were only a handful of simple operators and a notation for functions, you can just define a new function to add them.2 One thing we'll need is support for the new way that server-based, and the big bang method, is exemplified by the VC-backed, heavily marketed startup. A lot went wrong, as usually happens with startups. Most of the persecution comes from kids lower down, the nervous middle classes. Among companies, the best early adopters are forgiving when you improve your language, unless your language happens to be intended for writing compilers.3
We did go fast, but we couldn't afford to send a team of eight to ten people wearing jeans to the office and typing into vt100s. See if you can make changes almost as you would with desktop software: you should be able to do that is to get some initial set of users by doing a comparatively untargeted launch, and then see what they do: you call a function on the macro's arguments, and whatever it returns gets inserted in place of the macro call. And if teenagers respected adults more, adults also had more use for teenagers.4 I think part of the mechanism of popularity. It works a lot better for a small organization. But what kills them will not be about whether to make your software the standard—or who might buy a copy later, when he graduates from high school. You have the users' data right there on your disk. You build something, make it available, and if Microsoft doesn't control the client, they can't get that mad, because they have no state, and that is very convenient in a situation where you are. You have to use it. During the panel, Guy Steele also made this point, with the additional suggestion that the application should not consist of writing the compiler for your language, but they weren't crazy.
A popular programming language should be interactive, and start up fast.5 In either case there's not much you can learn from them. Hackers are lazy, in the end. To them the thought of average intelligence is unbearable. You know how you can design programs to be debuggable? If they made the experience good enough, audiences might start to prefer it to watching pirated movies at home.6 After trying the demo, signing up for the service should require nothing more than filling out a brief form the briefer the better.
We felt pretty lame at the time. This may not be the only way to deliver software that will save users from becoming system administrators. As I was leaving I offered it to him, as I've done countless times before in the same way that mathematicians and modernist architects are lazy: they hate anything extraneous. I read this book in school. A few months ago I ran into a friend in a cafe. When you're hosting software, someone has to be inexpensive and well-designed. You can figure out the rest as you go. It's a common mistake among inexperienced founders to believe that a partnership with a big company it's necessarily the dominant one. But while I'd spent a lot of parentheses.7 Then the interface will tend to push even the organizations issuing credentials into line. History offers little encouragement.
See if you can make changes almost as you would in a program you were writing for yourself.8 Are some people just a lot more independent than others, or would everyone be this way if they were allowed to? The good news is, simple repetition solves the problem.9 In the US this process still shows many outward signs of corruption.10 Nerds aren't losers.11 With the rise of Web-based applications, meaning programs that sit on the server, with SSL included, for less than the cost of selling expensive things to them. The thing about ideas, though, are busy. There are certainly great public school teachers. Too bad.
Notes
It's not simply a function of two founders and realized they were already lots of opportunities to sell earlier than you think you'll need, maybe 50% to 100% more, while she likes getting attention in the cupboard, but have no connections, you'll have to choose between the top 15 tokens, because at one point they worried Lotus was losing its startup edge and turning into a big deal. The two are not one of the causes of failure would be worth it for you; you're too early if it's convertible debt, so presumably will the rate of change in response to what modernist architects meant. The solution to that knowledge was to become one of the largest household refrigerators, weighs 656 pounds.
And it's particularly damaging when these investors flake, because companies then were more dependent on banks for capital for expansion.
Treating high school. For founders who continued to sit on corporate boards till the Glass-Steagall act in 1933. The average B-17 pilot in World War II, must have seemed an outlying data point that could evolve into a great reputation and they're clearly working fast to get market price, any YC partner wrote: After the war it was very much better is a declaration of war on.
Nat. No, we don't have to do business with any firm employing anyone who had to both left and right. I believe, and suddenly they need them to justify choices inaction in particular made for other reasons, including principal and venture partner.
We react like children, we're going to give you money for depends on where you wanted to make you expend as much the better, for example, probably did more drugs in his early twenties. You'll be lucky if fundraising feels pleasant enough to be when I was there was near zero crossover. VCs, I use. As one very successful YC founder told me: Another approach would be very promising, because they insist you dilute yourselves to set aside for this essay talks about the team or their determination and disarmingly asking the right startup.
One YC founder wrote after reading a draft, Sam Rayburn and Lyndon Johnson.
At this point for me, I should add that we're not. In practice it just feels like a VC means they'll look bad if that means having type II startups neither require nor produce startup culture. The founders want the valuation is the fact that you're not even be worth starting one that did.
If you actually started acting like adults, it would certainly be less than a Web browser that was actively maintained would be. 25 people have responded to this talk became Why Startups Condense in America consider acting white.
If they're on boards of directors they're probably a real poet. Turn the other cheek skirts the issue; the Reagan administration's comparatively sympathetic attitude toward takeovers; the crowds of shoppers drifting through this huge mall reminded George Romero of zombies.
But you can't, notably ineptitude and bad measurers. At two years investigating it. When we got to see.
What they forget is that some of those sentences. For more on not screwing up than any design decision, but this would be to write an essay about why people dislike Michael Arrington. If he's bad at it, and credit card debt stupidest of all.
0 notes
seocompany35203 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
restateagnt17101 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
repumktg61602 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
constructionsworkr3053 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
suzanneshannon · 5 years ago
Text
Neumorphism and CSS
Neumorphism (aka neomorphism) is a relatively new design trend and a term that’s gotten a good amount of buzz lately. It’s aesthetic is marked by minimal and real-looking UI that’s sort of a new take on skeuomorphism — hence the name. It got its name in a UX Collective post from December 2019, and since then, various design and development communities have been actively discussing the trend, usually with differing opinions. Chris poked fun at it on Twitter. Adam Giebl created an online generator for it. Developers, designers, and UX specialists are weighing in on the topic of aesthetics, usability, accessibility, and practicality of this design trend.
Clearly, it’s stricken some sort of chord in the community.
Let’s dip our toes into the neumorphism pool, showcasing the various neumorphic effects that can be created using our language of choice, CSS. We’ll take a look at both the arguments for and against the style and weigh how it can be used in a web interface.
Neumorphism as a user interface
We’ve already established that the defining quality of neumorphism is a blend of minimalism and skeuomorphism. And that’s a good way to look at it. Think about the minimal aesthetic of Material Design and the hyper-realistic look of skeuomorphism. Or, think back to Apple’s design standards circa 2007-12 and compare it to the interfaces it produces today.
Tumblr media
Nine years of Apple Calendar! The image on the left is taken from 2011 and exhibits the look and feel of a real, leather-bound journal, said to be inspired by one on Steve Jobs’ personal yacht. The right is the same app as shown today in 2020, bearing a lot less physical inspiration with a look and feel we might describe as “flat” or minimal.
If we think about Apple’s skeuomorphic designs from earlier in the century as one extreme and today’s minimal UI as another, then we might consider neumorphism as something in the middle.
Tumblr media
Alexander Plyuto has championed and evolved neomorphic designs on his Dribbble account. (Source)
Neumorphic UI elements look like they’re connected to the background, as if the elements are extruded from the background or inset into the background. They’ve been described by some as “soft UI” because of the way soft shadows are used to create the effect.
Another way to understand neumorphic UI is to compare it to Material Design. Let’s use a regular card component to draw a distinction between the two.
Tumblr media
Notice how the Material Design card (left) looks like it floats above the background, while the neumorphic variation(right) appears to be pushed up through the background, like a physical protrusion.
Let’s break down the differences purely from a design standpoint.
QualityMaterial DesignNeomorphismShadowsElements have a single or multiple dark shadows around them. Elements have two shadows: one light and one dark.Background colorsAn element’s background color can be different than the background color of the parent element.Background colors must be the same (or very similar) as the background color of the parent element.EdgesElements can be rounded or squared.Rounded edges are a defining quality.BordersThere are no hard rules on borders. Using them can help prevent elements that look like they are floating off the screen.Elements can have an optional subtle border to improve contrast and make the edges a bit sharper
That should draw a pretty picture of what we’re talking about when we refer to neumorphism. Let’s move on to how it’s implemented in CSS.
Neumorphism and CSS
Creating a neumorphic interface with CSS is seemingly as easy as applying a regular box-shadow property on any element, but it’s more nuanced than that. The distinctiveness of a neumorphic UI comes from using multiple box-shadow and background-color values to achieve different types of effects and variations.
Neumorphic box shadows
Let’s do a quick refresher on the box-shadow property first so we can get a better understanding. Here’s the syntax:
box-shadow: [horizontal offset] [vertical offset] [blur radius] [optional spread radius] [color];
Following options can be adjusted:
Horizontal offset: A positive value offsets shadow to the right, while a negative value offsets it to the left.
Vertical offset: A positive value offsets shadow upwards, while a negative value offsets it downwards.
Blur Radius: The length of the shadow. The longer the length, the bigger and lighter the shadow becomes. There are no negative values.
Spread Radius: This is another length value, where larger values result in bigger, longer shadows.
Color: This defines the shadow’s color, just as we’d do for the CSS color property.
Inset: The default value (initial) results in a drop shadow. Using the inset value moves the shadow inside the frame of the element, resulting in an inner shadow.
We can apply multiple shadows using comma-separated box-shadow values. Up to four values can be concatenated, one for each side of the box.
box-shadow: 20px 20px 50px #00d2c6, -30px -30px 60px #00ffff;
The following shows the box-shadow property values for a neumorphic UI element. Individual offset, blur and opacity values can be adjusted to be higher or lower, depending on the size of an element and the intensity of the effect that you’re trying to achieve. For neumorphism, it’s required to keep the shadows soft and low contrast.
CodePen Embed Fallback
As we’ve mentioned before, a core part of neumorphic elements is the use of two shadows: a light shadow and a dark shadow. That’s how we get that sort of “raised” effect and we can create variations by changing the “light source” of the shadows.
Two positive and two negative offset values need to be set. Taking this into account, we get the following four combinations, simply by changing the placement of each shadow.
CodePen Embed Fallback
Let’s use CSS variables to keep the values abstract and better understand the variations.
box-shadow: var(--h1) var(--v1) var(--blur1) var(--color-dark), var(--h2) var(--v2) var(--blur2) var(--color-light);
Light SourcePositive ValuesNegative ValuesTop Left--h1, --v1--h2, --v2Top Right--h2, --v1--h1, --v2Bottom Left--h1, --v2--h2, --v1Bottom Right--h2, --v2--h1, --v1
We can use inset shadows to create yet more variations. Unlike drop shadows that make an element appear to be raised from beneath the background, an inset shadow gives the appearance that the element is being pressed into it.
We can change if the element is extruded from the background or inset into the background by applying the initial (not apply the option at all) or inset, respectively.
Let’s keep our light source as the top left and only toggle the inset option to see the difference.
CodePen Embed Fallback
Background colors
You might have noticed that the box-shadow values change the look of the edges of a neumorphic element. So far, we haven’t changed the background-color because it needs to be transparent or have the same (or similar) color as a background color of an underlying element, such as the element’s parent. 
We can use both solid and gradient backgrounds. Using a solid color background on the element can create a flat surface sort of look, when that solid color is the same as the color of the underlying element. 
On the other hand, using subtle gradients can change how the surface is perceived. As with the box-shadow property, there is alight and a dark value in a gradient. The gradient angle needs to be adjusted to match the light source. We have the following two variations when using gradients:
Convex surface variation:  The surface curves outwards where the gradient’s lighter section is aligned with the shadow’s lighter section, and the gradient’s darker section is aligned to the shadow’s darker section.
Concave surface variation:  The surface curves inward where the gradient’s lighter section is aligned to the shadow’s darker section, and the gradient’s darker section is aligned to the shadow’s lighter section.
.element {   background: linear-gradient(var(--bg-angle), var(--bg-start), var(--bg-end));   box-shadow: var(--h1) var(--v1) var(--color-dark),                var(--h2) var(--v2) var(--color-light); }
CodePen Embed Fallback
Neumorphism in practice
Let’s see how Neumorphism performs when applied to a simple button. The main characteristic of a neumorphic interface is that it blends with the background and does so by having a similar or same background color as the underlying element. The main purpose of many buttons, especially a primary call-to-action, is to stand out as much as possible, usually with a prominent background color in order to separate it from other elements and other buttons on the page.
The background color constraint in neumorphism takes away that convenience. If the background color of the button matches the background color of what it’s on top of, we lose the ability to make it stand out visually with a unique color.
We can try and adjust text color, add a border below the text, add an icon or some other elements to increase the visual weight to make it stand out, etc. Whatever the case, a solid background color on a neumorphic button seems to stand out more than a gradient. Plus, it can be paired with an inset shadow on the active state to create a nice “pressed” effect.
Tumblr media
Even though the solid color on a neumorphic button calls more attention than a gradient background, it still does not beat the way an alternate color makes a button stand out from other elements on the page.
Taking some inspiration from the real-world devices, I’ve created the following examples as an attempt to improve on the neumorphic button and toggle concept. Although the results look somewhat better, the regular button still provides a better UX, has much fewer constraints, is more flexible, is simpler to implement, and does a better job overall.
CodePen Embed Fallback
The first example was inspired by a button on my router that extrudes from the device and has a sticker with an icon on it. I added a similar “sticker” element with a solid color background as well as a slight inset to add more visual weight and make it stand out as closely as possible to the ideal button. The second example was inspired by a car control panel where the button would light up when it’s in an active (pressed) state.
Let’s take a look at some more HTML elements. One of the downsides of neumorphism that has been pointed out is that it shouldn’t be applied to elements that can have various states, like inputs, select elements, progress bars, and others. These states include:
User interaction: Hover, active, focus, visited
Validation states: Error, success, warning, disabled
UX and accessibility rules require some elements to look different in each of their respective validation states and user interaction states. Neumorphism constraints and restrictions severely limit the customization options that are required to achieve the different styles for each possible state. Variations will be very subtle and aren't possibly able to cover every single state.
Tumblr media
Everything looks like a button! Notice how the input and button look similar and how the progress bar looks like a scrollbar or a really wide toggle.
It’s hard to see which elements are clickable! Even though this is the simplest possible example that showcases the issue, we could have added extra elements and styles to try and mitigate the issues. But as we’ve seen with the button example, some other types of elements would still perform better in terms of UX and accessibility.
It’s important to notice that Neumorphic elements also take more space (inside padding and outside margin) due to the shadow and rounded corners. A neumorphic effect wouldn’t look so good on a small-sized element simply because the visual effects consume the element.
The ideal element for neumorphism are cards, or any other static container element that doesn’t have states based on user interaction (e.g. hover, active and disabled) or validation (e.g. error, warning, and success).
In his highly critical article on neumorphism, Michal Malewicz (who helped coin “Neumorphism” as a term) suggests adding Neumorphic effects to the cards that already look good without it.
So the only way it works OK is when the card itself has the right structure, and the whole extrusion is unnecessary for hierarchy.
See?
It works well when it can be removed without any loss for the product.
Accessibility and UX
We’ve seen which elements work well with neumorphism, but there are some important rules and restrictions to keep in mind when adding the effect to elements.
First is accessibility. This is a big deal and perhaps the biggest drawback to neumorphism: color contrast.
Neumorphic UI elements rely on multiple shadows that help blend the element into the background it is on. Using subtle contrasts isn’t actually the best fit for an accessible UI. If a contrast checker is scanning your UI, it may very well call you out for not having high enough contrast between the foreground and background because shadows don’t fit into the equation and, even if they did, they’d be too subtle to make much of a difference.
Here are some valid criticisms about the accessibility of a neumorphic design:
Users with color blindness and poor vision would have difficulty using it due to the poor contrast caused by the soft shadows.
Page hierarchy is difficult to perceive when the effect is overused on a page. No particular element stands out due to the background color restrictions.
Users can get confused when the effect is overused on a page. Due to the extrusion effect, it’s difficult to determine which elements users can interact with and which are static.
In order to achieve a good contrast with the shadow, the background color of what a neumorphic element sits on shouldn’t get too close to the edges of RGB extremes (white and black).
Now let’s talk UX for a moment. Even though Neumorphic UI looks aesthetically pleasing, it shouldn’t be a dominant style on a page. If used too often, the UI will have an overwhelmingly plastic effect and the visual hierarchy will be all out of whack. Ae page could easily lose its intended structure when directing users to the most important content or to the main flow.
My personal take is that neumorphism is best used as an enhancement to another style. For example, it could be paired with Material Design in a way that draws distinctions between various component styles. It’s probably best to use it sparsely so that it adds a fresh alternative look to something on the screen — there’s a diminishing return on its use and it’s a good idea to watch out for it.
Here’s an  example where neumorphic qualities are used on card elements in combination with Materialize CSS:
CodePen Embed Fallback
See, it can be pretty nice when used as an accent instead of an entire framework.
That’s a wrap
So that was a deep look at neumorphism. We broke down what makes the style distinct from other popular styles, looked at a few ways to re-create the effect in CSS, and examined the implications it has on accessibility and user experience.
In practice, a full-scale neumorphic design system probably cannot be used on a website. It’s simply too restrictive in what colors can be used. Plus, the fact that it results in soft contrasts prevents it from being used on interactive elements, like buttons and toggle elements. Sure, it’s aesthetically-pleasing, modern and unique, but that shouldn’t come at the expense of usability and accessibility. It should be used sparsely, ideally in combination with another design system like Material Design.
Neumorphism is unlikely to replace the current design systems we use today (at least in my humble opinion), but it may find its place in those same design systems as a fresh new alternative to existing cards and static container styles.
References
Neumorphism in user interfaces
Neumorphism — the zombie trend
Let’s talk Neumorphism and Accessibility
The post Neumorphism and CSS appeared first on CSS-Tricks.
Neumorphism and CSS published first on https://deskbysnafu.tumblr.com/
0 notes
lxryrestate28349 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
repmrkting17042 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
restatebrk24219 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes
bathrem22032 · 7 years ago
Text
Guide to AdWords Conversion Tracking in 2018
Guide to AdWords Conversion Tracking in 2018
When adding Google AdWords conversions to your website, recent changes to the AdWords interface has introduced some confusion for new and veteran AdWords users. If you’ve created an AdWords conversion lately, you have probably noticed new instructions for implementing the tracking pixel.
There are two common reactions: shock and fear – where did my familiar instructions go?! I’ve done this 100 times and now it’s different? Or perhaps you were a little excited at the idea of an all-new, fully loaded Global Site Tag. Before you go full-steam ahead or pull your hair out, I’m here to say pump the brakes.
Let’s talk about what the Global Site Tag (gtag.js) means for tracking AdWords Conversions in 2018.
Take a Step Back – What Does gtag.js Actually Do?
So you create a new conversion and AdWords gives you new Global Site Tag instructions, but what do they mean? This isn’t a blog post about the purpose or future of gtag.js (Amanda already wrote a fine post on that subject), but we need to explain what this new tool will do for you, and more importantly, what it won’t.
What Is gtag.js with Google Analytics and Do I Need It?
By: Amanda Schroeder Published: December 12, 2017
Keep Reading >
With conversion tracking in mind, here are a few things to know before you make a move:
gtag.js is not required to simply add an AdWords conversion tag to your site.
It is not actually a conversion tag. There are two parts, the first is general for AdWords. The event snippet associated with the tag (lower on instruction page) is for recording conversions.
The code, gtag.js, is not a new Google Analytics library. Re: Amanda’s post.
These updated instructions will not help track conversions from Safari. For this, Google created the Conversion Linker.
It is not the Rosetta Stone of attribution. Just because it’s new, doesn’t mean it will provide additional data about multi-channel attribution.
The bottom line is that gtag.js primarily streamlines implementation and use of Google tools (like Google Analytics and Google AdWords) by loading them through one, on-page code. But it’s still very new, so a lot of variables will determine how you proceed. It all depends on the use case:
Scenario One: I’m using Google Tag Manager Our Recommendation: Do not implement gtag.
Google Tag Manager already does most of what gtag intends to go. If you have created any tags through GTM, moving to gtag creates extra work. Instead, you can quickly create a conversion tag in GTM using some information on the AdWords conversion page.
On the same tag setup page that offers gtag, scroll further to find the Event Snippet that works with gtag.js. There are two key pieces of information you will need.
Use these values to create a Google AdWords conversion with GTM’s built-in tag. The requires two values. For the Conversion ID, add the string of numbers after “AW-” and before the slash (underlined in orange above). For Conversion Label, add the sting after the slash (underlined in blue above).
No need to worry about the pageview/click option back in AdWords. Your GTM trigger will take care of that for you.
Scenario Two: Advanced Universal Analytics Code On-Page Our Recommendation: Do Not Implement gtag
If you have Universal Analytics code on-page and are using any sort of customization to send events, virtual pageviews or other unique data to Analytics, you will likely not want to switch to gtag.js. That would mean updating all on-page customized code to the new gtag syntax. Not sure if you have custom code? Any use of custom dimensions, custom metrics, or events is likely relying on your current implantation of Universal Analytics.
In this case, you want to dig up the legacy AdWords conversion pixel. One easy way to do this is switch back to the old AdWords interface. Just hit the wrench icon in AdWords and click “Return to Previous Interface.”
If you want to go the harder route, you can add the Conversion Label and ID back into an old version of the code, but heed Google’s troubleshooting to make sure you cover all your bases. For example, the http/https value in the tag must match the value of the page.
Scenario Three: Basic Code On-Page, GTM Not Possible Our Recommendation: You Are Clear For gtag
If you’ve got just the basics on your site, you could definitely consider upgrading. Of course, we’ll always suggest GTM (see Amanda’s post), but if that’s possible, gtag is still a great option. In this case, you can replace your current implementation of Google Analytics with gtag.js. It’s important to remember a few things:
You need to load both Google Analytics and Google AdWords libraries using both gtag(‘config’, ‘[GA_TRACKING_ID]’); and gtag(‘config’, AW-[ACCOUNT_NUMBER]’). This will load Analytics.js and ensure all of your conversion pixels fire.
Include following event snippet on the conversion page.
Why All the Trouble?
The AdWords conversion tracking question gets to the root of gtag.js. Ultimately, the new implementation instructions are designed to be easier for new websites that want to track across multiple Google products, like Google Analytics and Google AdWords, with minimal customization. It can offer consistent information across Google Analytics, Google AdWords, and DoubleClick – and for a new digital marketer, this setup will appear more cohesive and simpler to implement.
But when it comes to seasoned digital marketers or advanced Google Analytics tracking, things get a little trickier. While Gtag may be simpler for on-page code compared to the previous analytics.js implementations and AdWords conversion tags, it still requires you to make changes directly on your site. If you are primarily interested in AdWords and DoubleClick, and you typically add tags to your website via JavaScript on the page, then this new format may simplify your life. If you have been using Google Analytics or Google Tag Manager before, or are interested in utilizing more robust features, Google Tag Manager may be the better implementation solution.
http://ift.tt/2Fuf8yH
0 notes