Creating CSS Shapes with Emoji

CSS Shapes is a standard that lets us create geometric shapes over floated elements that cause the inline contents — usually text — around those elements to wrap along the specified shapes.

Such a shaped flow of text looks good in editorial designs or designs that work with text-heavy contents to add some visual relief from the chunks of text.

Here’s an example of CSS Shape in use:

The shape-outside property specifies the shape of a float area using either one of the basic shape functions — circle(), ellipse(), polygon() or inset() — or an image, like this:

Inline content wraps along the right side of a left-floated element, and the left side of a right-floated element.

In this post, we’ll use the concept of CSS Shapes with emoji to create interesting text-wrapping effects. Images are rectangles. Many of the shapes we draw in CSS are also boxy or at least limited to standard shapes. Emoji, on the other hand, offers neat opportunities to break out of the box!

Here’s how we’ll do it: We’ll first create an image out of an emoji, and then float it and apply a CSS Shape to it.

I’ve already covered multiple ways to convert emojis to images in this post on creative background patterns. In that I said I wasn’t able to figure out how to use SVG <text> to do the conversion, but I’ve figured it out now and will show you how in this post.  You don’t need to have read that article for this one to make sense, but it’s there if you want to see it.

Let’s make an emoji image

The three steps we’re using to create an emoji image are:

  • Create an emoji-shaped cutout in SVG
  • Convert the SVG code to a DataURL by URL encoding and prefixing it with data:image/svg+xml
  • Use the DataURL as the url() value of an element’s background-image.

Here’s the SVG code that creates the emoji shaped cutout:

<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> 
  <clipPath id='emojiClipPath'> 
    <text x='0' y='130px' font-size='130px'>🦕</text> 
  </clipPath> 
  <text x='0' y='130px' font-size='130px' clip-path='url(#emojiClipPath)'>🦕</text>
</svg>

What’s happening here is we’re providing a <text> element with an emoji character for a <clipPath>. A clip path is an outline of a region to be kept visible when that clip path is applied to an element. In our code, that outline is the shape of the emoji character.

Then the emoji’s clip path is referenced by a <text> element carrying the same emoji character, using its clip-path property, creating a cutout in the shape of the emoji.

Now, we convert the SVG code to a DataURL. You can URL encode it by hand or use online tools (like this one!) that can do it for you.

Here’s the resulted DataURL, used as the url() value for the background image of an .emoji element in CSS:

.emoji {
  background: url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦕</text> </clipPath> <text x='0' y='130px' font-size='130px' clip-path='url(%23emojiClipPath)'>🦕</text></svg>");
}

If we were to stop here and give the .emoji element dimensions, we’d see our character displayed as a background image:

Now let’s turn this into a CSS Shape

We can do this in two steps:

  • Float the element with the emoji background
  • Use the DataURL as the url() value for the element’s shape-outside property
.emoji {
  --image-url: url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦕</text> </clipPath> <text x='0' y='130px'  font-size='130px' clip-path='url(#emojiClipPath)'>🦕</text></svg>");
  background: var(--image-url);
  float: left;
  height: 150px;
  shape-outside: var(--image-url);
  width: 150px;
  margin-left: -6px; 
}

We placed the DataURL in a custom property, --image-url, so we can easily refer it in both the background and the shape-outside properties without repeating that big ol’ string of encoded SVG multiple times.

Now, any inline content near the floated .emoji element will flow in the shape of the emoji. We can adjust things even further with margin or shape-margin to add space around the shape.

If you want a color-blocked emoji shape, you can do that by applying the clip path to a <rect> element in the SVG:

<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> 
    <clipPath id='emojiClipPath'> 
        <text x='0' y='130px' font-size='130px'>🦕</text> 
    </clipPath> 
    <rect x='0' y='0' fill='green' width='150px' height='150px' clip-path='url(#emojiClipPath)'/> 
</svg>

The same technique will work with letters!

Just note that Firefox doesn’t always render the emoji shape. We can work around that by updating the SVG code.

<svg xmlns='http://www.w3.org/2000/svg' width='150px' height='150px'>
  <foreignObject width='150px' height='150px'>
    <div xmlns='http://www.w3.org/1999/xhtml' style='width:150px;height:150px;line-height:150px;text-align:center;color:transparent;text-shadow: 0 0 black;font-size:130px;'>🧗</div>
  </foreignObject>
</svg>

This creates a block-colored emoji shape by making the emoji transparent and giving it text-shadow with inline CSS. The <div> containing the emoji and inline CSS style is then inserted into a <foreignObject> element of SVG so the HTML <div> code can be used inside the SVG namespace. The rest of the code in this technique is same as the last one.

Now we need to center the shape

Since CSS Shapes can only be applied to floated elements, the text flows either to the right or left of the element depending on which side it’s floated. To center the element and the shape, we’ll do the following:

  • Split the emoji in half
  • Float the left-half of the emoji to the right, and the right-half to the left
  • Put both sides together!

One caveat to this strategy: if you’re using running sentences in the design, you’ll need to manually align the letters on both sides.

Here’s what we’re aiming to make:

First, we see the HTML for the left and right sides of the design. They are identical.

<div id="design">
  <p id="leftSide">A C G T A <!-- more characters --> C G T A C G T A C G T <span class="emoji"></span>A C G <!-- more characters --> C G T </p>
  <p id="rightSide">A C G T A <!-- more characters --> C G T A C G T A C G T <span class="emoji"></span>A C G <!-- more characters --> C G T </p>
</div>

p#leftSide and p#rightSide inside #design are arranged side-by-side in a grid.

#design {
  border-radius: 50%; /* A circle */
  box-shadow: 6px 6px 20px silver;
  display: grid; 
  grid: "1fr 1fr"; /* A grid with two columns */
  overflow: hidden;
  width: 400px; height: 400px;
}

Here’s the CSS for the emoji:

span.emoji {
  filter: drop-shadow(15px 15px 5px green);
  shape-margin: 10px;
  width: 75px; 
  height: 150px;
}

/* Left half of the emoji */
p#leftSide>span.emoji {
  --image-url:url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦎</text> </clipPath> <rect x='0' y='0' width='150px' height='150px' clip-path='url(%23emojiClipPath)'/></svg>");
  background-image: var(--image-url);
  float: right;
  shape-outside: var(--image-url);
}

/* Right half of the emoji */
p#rightSide>span.emoji {
  --image-url:url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='-75px' y='130px'  font-size='130px'>🦎</text> </clipPath> <rect x='0' y='0' width='150px' height='150px' clip-path='url(%23emojiClipPath)'/></svg>");
  background-image: var(--image-url);
  float: left;
  shape-outside: var(--image-url);
}

The width of the <span> elements that hold the emoji images (span.emoji) is 75px whereas the width of the SVG emoji images is 150px. This automatically crops the image in half when displayed inside the spans.

On the right side of the design, with the left-floated emoji (p#rightSide>span.emoji), we need to move the emoji halfway to the left to show the right-half, so the x value in the <text> in the DataURL is changed to 75px. That’s the only difference in the DataURLs from the left and right sides of the design.

Here’s that result once again:


That’s it! You can try the above method to center any CSS Shape as long as you can split the element up into two and put the halves back together with CSS.


The post Creating CSS Shapes with Emoji appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Yext Launches a WordPress Plugin To Connect To Its Answers Platform

Last week, Yext launched its Yext Answers plugin to the WordPress community. The goal was to bring a platform that won the Best Software Innovation category of the 2020 Global Search Awards to WordPress. However, my experience was far from satisfactory.

“For people searching on a WordPress website, the Answers Connector provides a seamless search experience,” said Alexandra Allegra, the Senior Product Marketing Manager at Yext. “For businesses and organizations that integrate it, it drives higher rates of conversion, which generates more revenue. It helps lower support costs because when businesses can deliver detailed, official answers, customers don’t have to call customer service. And finally, it unveils valuable customer insights, because businesses can see new questions coming in — in real-time.”

Yext Answers is essentially trialware. Technically, the plugin itself is free. However, Yext is currently running a 90-day free trial for access to its Answers platform. The website does not seem to provide an easy way to find what the true cost will be after that initial 90 days. To upgrade, users must contact the Yext team via email or phone.

The website does provide an estimated cost calculator. The lowest tier available via this calculator is for 20,000 searches per month at $5,000. It is unclear if there are lower pricing options. The Yext team provided no further details when asked about billing.

The plugin is marketing itself primarily toward business users. It can replace a WordPress site’s traditional search, which is customizable to suit various site owner’s needs, according to the Yext team.

Over the past week, I have discussed this plugin with a representative from the company, watched demo videos, and attempted to test the plugin. Thus far, it has been a subpar experience. I typically forgo writing about plugins that do not pan out. However, after the initial investment into what looked to be an interesting project, I wanted to share my experience, and my hope is that it helps the team build a better product in the long term.

I have yet to get the Yext Answers plugin to work. It requires an account with the Yext website. It also requires that end-users enter multiple fields on the plugin settings screen in WordPress. Unfortunately, after a frustrating amount of searching, I was never able to successfully find all of the correct information or get the information I did have to work. I gave up on the endeavor.

The demo video does show the promise of a somewhat interesting plugin:

Perhaps people who are already familiar with the Yext platform may have better luck. However, I would not recommend it to anyone new, at least in its current state.

There are far better options for connecting via third-party APIs that would be simpler for the average end-user (or even a developer of 15+ years such as myself). The one-click login process provided via the MakeStories plugin, which I covered recently, is a prime example of how to do things right.

We are at a point in the internet era in which end-users should have simple, no-fuss connections between sites. Entering IDs, keys, and other complex fields should be tucked under an “advanced” section of the options screen, not as part of the default experience. Or, they should be so easily available that no one should have trouble finding them.

Launching with Shortcodes Instead of Blocks

Two years after the integration of the block editor into WordPress, the Yext team is launching its Yext Answers plugin with shortcodes, which require manual entrance by end-users. Currently, the plugin does not have block equivalents for its shortcodes.

The team was either unwilling or unable to answer even the most fundamental questions about their decision to use shortcodes rather than launching their plugin — in the year 2020 — with at least block alternatives. At points, they even seemed confused about the subject altogether.

The closest the team came to providing feedback after a lengthy discussion was the following, attributed to Rose Grant, the Associate Product Manager:

We’re looking forward to feedback on the initial release of our plugin before iterating further on it, including introducing custom blocks. For this version of the plugin, we wanted to prioritize supporting clients who are using older versions of WordPress.

Packaging a set of shortcodes within a plugin is still a good practice, even for plugin developers who have transitioned fully to supporting the block editor. It allows them to support users who are still working with the classic editor. However, at this point, developers should be building from a block-first mindset. Blocks do not require that users remember specific shortcode names. They provide instant, visual feedback to users in the editor. And, block options (as opposed to shortcode arguments) do not rely on the oftentimes faulty input of user typing.

At this point, all plugin developers should consider shortcodes a legacy feature and useful only as a backward-compatible option for users on the classic editor.

The Communications Strategist for the company pointed out that this is Yext’s first venture into WordPress plugins and that the team may not be able to provide perspective or commentary on such questions related to blocks and shortcodes. However, this is the third Yext-related plugin associated with the plugin author account on WordPress.org.

How Kubernetes Exemplifies A Truly API Driven Application

When most people think of APIs, they think of a backend access point for client-server interactions in a distributed application. For many situations, this is indeed its purpose. But, an API can be much more than an interface between server-side logic and public consumers of that logic. For example, it is entirely possible to make it so that an API layer serves as the master control center for all activity taking place inside and outside a computing domain.

How To Overcome Data Onboarding Challenges For Software Products

Companies willing to pay good money for a new piece of software are most likely not starting from scratch. They’re running an established business, with well-built and documented processes. So, they have tons of data to carry over.

As a result, the decision to bring a new app into the fold is not one they take lightly. Internal processes need to change. Getting the team to adopt the new solution can take time. Integrating it with existing systems and external tools can be a problem. Oh yeah, and there’s the matter of compliance to worry about, too.

This means there’s a lot of pressure on new software to provide a top-notch experience from the get-go. Fail to provide companies with a simple and intuitive way to onboard their data and you can expect high rates of customer churn as a result.

If you’re designing a product that needs data from customers in order to be of any value, here’s what you need to know about building out your data onboarding process.

How Data Onboarding Correlates With User Satisfaction

Business software is essentially just an empty box waiting to be filled with its users’ data. Without the ability to flawlessly onboard users’ data, the software essentially becomes useless.

Let’s look at what happens when you get the data onboarding process right.

End User Benefits

If you can nail the data onboarding piece, expect your end users to reap the following benefits:

  • They’ll be more confident in their decision.
    With complete and accurate data transferred into your software, users actually see how valuable it is soon after signing up. This leaves little room for second-guessing their decision, which leads to greater satisfaction overall with the product, and ultimately more money for your business.
  • You’ll get greater team buy-in.
    A positive data onboarding experience lets customers use your product faster, reducing the time needed for them to get value. So, really, data onboarding sets the stage for how your customers and their team will view the rest of your app.
  • They’ll experience more success with the software.
    Since users won’t have to stress about data formatting and cleanup or troubleshooting error-ridden import processes, they can get more out of the product and its features.

Software Developer Benefits

The software provider (you and/or your client) benefits, too:

  • Improve user satisfaction.
    Your end users don’t need to be technical wizards to figure out how to onboard data into your product. When you make light work of this, you reduce churn, attract more users and retain more loyal users over the long-term.
  • Spend less time on customer service.
    You can stop worrying about having to support a faulty data onboarding process as well as taking over tasks like data formatting and validation for your users. Instead, put your time and energy towards building better relationships with customers instead of putting out fires all the time.
    Kelly Abbott, Co-Founder and CTO of Tablecloth, can attest to this:
    “We have cut the amount of time we spend wrangling with files by 95%. We basically had all hands working to solve those problems at times.”
  • Have greater confidence in your product.
    When you have a data onboarding solution that’s flexible and powerful, you don’t have to restrict what data your users can or can’t import. It’s no longer a limitation.
    As Abbott explains:
    “It has made us more contemplative about the data we are asking clients for. We no longer have to avoid asking for data that may require too much time to fix. Flatfile eliminates that problem and has improved our willingness to experiment with different types of data we can incorporate into our analyses. The more time we spend tinkering with different data types, the more likely we are going to uncover the insight that produces additional value in the marketplace. That is indispensable for a startup like us.”
  • Save money.
    Although you’ll have to spend money on a third-party data onboarding solution, you’ll save your company the time and money otherwise spent trying to manage a custom-built data importer, onboarding process and client relationships. (Tablecloth, for instance, saved tens of thousands of dollars when they adopted Flatfile.)

The Challenges Of Data Onboarding For Software Products

Let’s have a look at the common challenges in data onboarding and how Flatfile Concierge removes them:

Challenge #1: There’s A Lot Of Data To Aggregate

When signing up for new business software, users probably expect to do a little work upfront, like filling in basic account information, configuring settings and adding users. The last thing you want to do is surprise them with a data importer that’s going to cause more work for them.

Let’s say, for example, you’ve built a CRM.

Unless the software targets startups and other new businesses, users are going to have a ton of external data to bring along. For instance:

  • Contact info for clients, prospects, vendors, partners and team members;
  • Existing customer data like account and sales history;
  • Prospect data like communication history;
  • Sales pipeline details;
  • Team and individual goals and metrics.

Unless your CRM directly integrates with every one of your users’ previous CRMs, how are they going to move this data over? Copy and paste? CSV templates?

An animation demonstrating Flatfile Concierge data models. Companies can create specific data models as a guide for customers to use when importing data. (Image source: Flatfile)

Plus, you have to think about all of the other sources a CRM pulls info in from. Payment gateways. Spreadsheets that live on a sales team’s drive. Signed contracts that have been emailed or faxed to your company. There’s a lot of data coming from different places and people.

The Fix

There are a number of things Flatfile Concierge does to fix this problem.

For starters, it allows data to be imported from a variety of file types:

  • CSV,
  • TSV,
  • XLS,
  • XML,
  • And more.

With this kind of flexibility, your users won’t have to worry about transferring data to one specific file type and then cleaning up errors that occur during the transfer. Flatfile Concierge can handle various file types, of varying data types, and easily validate it all.

Another thing to think about is how your software is going to track and organize each imported file and its corresponding data.

What Flatfile allows your users to do is create collaborative workspaces to place data in. When a team member adds new data to the workspace, a record is captured containing the:

  • Date of upload,
  • File name,
  • User who submitted the data,
  • Number of rows added,
  • Version history,
  • Upload errors.
Flatfile Concierge animation demonstrating notifications for when spreadsheets are imported. (Image source: Flatfile)

This will keep things organized while also keeping everyone accountable to the data they contribute. And with this information readily available from a centralized dashboard, there’ll be no secret as to what’s been uploaded, by whom and when. Import errors can also be fixed collaboratively, without the need to re-upload spreadsheet data.

Challenge #2: Data Is Imported In A Variety Of States

When you give your software users the ability to transfer their data into your product, there’s not a lot you or the software team can do in terms of formatting or cleaning up end users’ data beforehand. Nor should you have to. Your job is to ensure customers see the value in the software; not to struggle with importing data.

You could give them a spreadsheet template, but that would require them to spend time reformatting all their data. You could point them to the knowledgebase, but, again, that assumes that your end users will be willing to do that extra work.

In reality, your users are going to be in a hurry to get inside the new software and get to work. They’re not going to stop to deal with this. That’s the software’s job.

However, many data onboarding solutions don’t handle messy spreadsheets very well. Not only do they have a hard time recognizing what some of the data is (often because the data model doesn’t match their own), but then the application refuses to accept certain spreadsheet columns.

Even if it’s the end user’s fault for not properly organizing or labeling their data or teaching their team how to do so (or just not knowing what to do in the first place), who do you think they’re going to blame in the end when their data won’t import?

The Fix

Flatfile Concierge’s importer is AI-powered, which means that your software (and data importer) really can do the work for your end users.

Using advanced validation logic, the data importer can figure out what the data is and where it goes.

While Flatfile will automatically match columns and corresponding data to your software’s actual data fields, users get a chance to confirm that’s the case before allowing it into the system:

Before this happens, you can do a little work on the backend to ensure that Flatfile knows what to do with your users’ data:

  • Create target data models so Flatfile can navigate complex spreadsheet formats and datatypes your users will likely try to import.
  • Create a template with validation rules so Flatfile’s AI knows exactly how to map everything out.
  • Validate imported data against other databases to help the importer contextualize, validate and clean up the data over time.

Once you’ve done that upfront work, the rest is easy.

The bulk of the work will be done by Flatfile Concierge when it transforms imported data into something clean and useful. In fact, about 95% of imported columns will automatically map to your software thanks to Flatfile’s machine learning and fuzzy matching system.

The end user will have the opportunity to review the parts of their data that contain errors. If they find any, they can repair the errors inside Flatfile, rather than have to fix it in a spreadsheet and re-import.

Challenge #3: Getting And Tracking Data From Multiple Users

When there are a lot of cooks in the kitchen, there are a number of things that can go wrong.

Data can sometimes live on team members’ computers, or worse, sent over email, which can be a huge security concern for sensitive data. This can happen if users aren’t given access to the software platform or find the data importer too intimidating to use.

On the flip side of that, with the wrong data onboarding process, it could become like a free-for-all where people add whatever the heck they like to the company’s data. While the data does get imported, there’s no review framework so the company’s database is filled with errors and duplicate entries.

Your end users need to be able to maintain order, control and security when dealing with something as serious as company data — especially if you want your software to be usable.

The Fix

Flatfile Concierge has designed the data onboarding process to be a collaborative one.

As you can see, company admins can invite specific collaborators (i.e. customers) to add data to their workspaces. But this isn’t a blanket invitation to import data.

Admins have the ability to create an approval process. They get to:

  • Ask for specific data sets from team members.
  • Control which workspaces they’re allowed to import data to.
  • Review all data submissions before flowing the approved data into the platform.

Admins can also import data on the customer’s behalf. Flatfile Concierge ensures that data onboarding is never a dead-end for customers.

Not only does this ensure that the right data ends up in the software, but the controlled flow means the data will end up being cleaner and more accurate, too. All of this, while providing a seamless data onboarding experience for users.

Challenge #4: Data Security Is Always A Concern

When it comes to web and app development, user privacy and security are top priority. If our customers and visitors don’t trust that their information is safe from prying eyes (and isn’t being sold off to advertisers), they’re going to stop using our solutions in the first place.

The same thing happens with software — though it’s not just the company’s personal data they have to worry about securing.

Often, when companies import data into software (like the CRM example), they’re importing their customers’ private and sensitive data. Allow that to be compromised and you can kiss your software goodbye.

So, yes, the software itself needs to be secured. That’s a given. But so, too, does your data onboarding process. It’s a huge point of vulnerability if left unchecked.

The Fix

The first thing Flatfile Concierge does is to encourage users to move away from sharing sensitive data over email, FTP, and other unsecured platforms by providing a user-friendly data onboarding solution.

The second thing it does is provide an authenticated and compliant workspace for users to import, validate, and post their data to your software.

Here’s how Flatfile Concierge secures its workspaces:

  • Each collaborator enters the data importer through an authenticated invitation.
  • Data is encrypted in transit and stored in an encrypted Amazon S3 bucket.
  • The data onboarding platform is 100% GDPR compliant.
  • Flatfile is HIPAA and SOC2 compliant and can adjust for other compliance requirements as needed.

In addition, once data is successfully migrated into your application, it’s deleted from Flatfile. This way, you only have to worry about securing your data within your software and not on previous platforms it’s touched.

Wrapping Up

With an insufficient or error-prone data onboarding process, you, the software provider and its end users are going to spend too much time manually cleaning and validating spreadsheets. This won’t just happen during the initial user signup either. If the data importer isn’t up to the task, you’re all going to be throwing away a ton of time and resources every time data needs to be uploaded or transferred into the platform from existing customers.

Of course, this all assumes that your importer can even get user data into the software. (Sadly, this happens with too many custom-built solutions.)

Needless to say: Your data onboarding process must be flawless for your team and customers. It’s the only way to keep user churn rates low and user satisfaction high.

Data onboarding is a really complex process to handle. Save yourself the trouble in trying to develop your own data onboarding solution and the time trying to troubleshoot the problems with it. With an AI-powered data importer like Flatfile Concierge, everything’s taken care of for you.

4 Ways Big Data Is Evolving Risk Management

In the digital era, Big Data has drastically changed the landscape of business and risk management. With unlimited access to information about potential customers and user behavior, companies are using analytics to improve their risk management practices in more advanced ways than ever before.

Big Data Analytics

Techwave's Big data analytics consulting services help you maximize revenue options and win loyal and happy customers.

Why Big Data Is Important

Big data has been around a long time, but it has taken a while for organizations to see the usefulness of big data. Big data doesn't just track the consumer when they are online - it provides a history of behaviors that big data services can analyze and extrapolate from. If the consumer uses smart devices, makes a purchase with credit cards or checks, or visits establishments that use smart devices, they leave a data trail that can be analyzed by big data consulting to determine possible trends. These trends help businesses understand what drives their customers to make certain purchases over others.

5 Things to Know Before Starting an AI Project

Suppose you have an opportunity to create a project on AI. Consider these five stages before starting. These five are learning, programming language, knowledge representation, problem solving, and hardware.

1. Learning Process

Learning means adding new knowledge to the knowledge base and improving or refining previous knowledge.

10 Tips for Transforming Into a High Performing Agile Team

Agile teams, like any, face their challenges. And while the agile method has often been discussed like a magic cure-all for organization and task efficiency, it’s got to be done properly in order to be successful.

Because the agile method is more than just a gimmick way of selling stuff. It is an efficient setup for businesses to use in order to boost productivity and cost-efficiencies.

Compare Multiple Projects With This GitHub Stats Tool

If you have project code hosted on GitHub, chances are you might be interested in checking some numbers and stats such as stars, commits, and pull requests.

You might also want to compare some similar projects in terms of the above-mentioned stats, for whatever reasons that interest you.

DevEverythingOps: Explained With Pizza, Butchering, and Soccer

BizDevOps. DevSecOps. DevTestOps. DevXOps. DevEverythingOps…

Call it whatever you want – the bottom line is that if you hyperfocus on bringing Dev and Ops together, you’re going to overlook a lot of the key elements required to release valuable software faster. Does it delight users? Satisfy business goals? Minimize quality and security risks? And how do you achieve all that without stifling speed and frustrating the original “proprietors” of DevOps: Development and Operations?

Gutenberg 9.2 Adds Video Tracks, Improvements to Columns and Cover Blocks

Gutenberg 9.2 was released this week and is the last release of the plugin to be rolled into WordPress 5.6. It features the long-awaited video tracks functionality, closing a ticket that has been open for more than two years under development.

Video tracks includes things like subtitles, captions, descriptions, chapters, and metadata. This update introduces a UI for adding video tags, which can contain multiple track elements using the following four attributes:

  • srclang (Valid BCP 47 language tag)
  • label (Title for player UI)
  • kind (Captions, Chapters, Descriptions, Metadata or Subtitles)
  • src (URL of the text file)

The ability to edit tracks is exposed in the video block’s toolbar:

This update closes a major gap in video accessibility and greatly improves the user experience of videos.

Gutenberg 9.2 also introduces the ability to transform multiple selected blocks into a Columns block. For example, users can select three image blocks and instantly change them into a three-column section. Columns can be created from any kind of block, including InnerBlocks. The transform option will appear if the number of selected blocks falls between 2-6. (The maximum number is derived from the maximum number of columns allowed by the Columns block.)

Transform multiple blocks into Columns block

Another notable feature in 9.2 is the expansion of Cover blocks to support repeated background patterns. This gives users more flexibility in their designs, opening up a new set of possibilities.

https://cloudup.com/cArDykzhpYZ

This release brings in more than a dozen improvements to the new Widgets screen, as well as updates to the Query Block and Site Editor experiments. The most notable smaller enhancements to existing features include the following:

  • Add dropdown button to view templates in sidebar. (26132)
  • Gallery block: Use image caption as fallback for alt text. (26082)
  • Table block: Use hooks + API v2. (26065)
  • Refactor document actions to handle template part titles. (26043)
  • Info panel layout improvement. (26017)
  • Remove non-core blocks from default editor content. (25844)
  • Add very basic template information dropdown. (25757)
  • Rename “Options” modal to “Preferences”. (25683)
  • Add single column functionality to the Columns block. (24065)
  • Add more writing flow options: Reduced UI, theme styles, spotlight. (22494)
  • Add option to make Post Featured Image a link. (25714)

Since the Gutenberg 9.2 release was delayed by a week, it includes many more bug fixes and code quality improvements than most releases. Check out the full changelog for more details.

How to Convert a PDF to PNG or JPG in Java

For sharing documents both in hardcopy and digitally, the PDF file format is the preferred choice. Because of its high-versatility and compatibility between different operating systems, the PDF format allows users to create, edit, encrypt, and lock important documents for viewing on any browser or with any PDF viewing application such as Adobe Acrobat. Furthermore, its flexibility means that almost any other file type can be converted into PDF format without loss of quality or corruption of formatting. This means that complex file types such as DOCX and XLSX documents can be converted and shared easily in a protected format that will limit the chance of accidental edits or formatting errors.

However, if you are planning to display examples or insert an image of a PDF document in a separate file or web page, converting your PDF files to an image array will be more useful. For example, if you are creating a PowerPoint showing the on-boarding process for your organization and need to include images of different documents or contracts associated with the process, converting your PDF files into JPG will allow you to quickly and effortlessly insert the image and scale or crop it according to the needs of your presentation. When performing a similar process for a web page, having your document available as a PNG image will optimize it for viewing online within your website. It also prevents users from downloading and editing the document as would be possible with a PDF.

Best of Dan Lines Collection

Anytime I see an article written by Dan Lines in my moderation queue, I know our audience is about to get some great content. His storytelling is consistent and engaging, and every article manages to leave readers with more tangible takeaways than the last. 

To celebrate his keynote at the Agile + DevOps Virtual conference, we've collected the Best of the Best from Dan Lines. (It wasn't easy... each one is so good!)

How to Search Emails in Gmail by Specific Time

Gmail supports a plethora of search operators to help you instantly find that elusive email message buried in your mailbox. You have size search - like larger_than:5mb - to find the big messages in your account. File search - like has:attachment filename:doc - will locate email messages that contain specific file attachments. This graphic illustrates all the known Gmail search operators that work both on Gmail website and mobile.

Gmail Search Tricks

Search by Date in Gmail

Date search in Gmail helps you locate emails sent or received during a specific period. Here are some examples:

  • newer_than:7d from:me - Emails sent in the last 7 days
  • after:2020/10/15 before:2020/10/20 from:uber - Emails from Uber received between October 15 and October 20.
  • newer_than:60d older_than:30d - All emails received in the previous 30-day range.

The date in the Gmail search query is specified in the YYYY/MM/DD format.

Search Emails by Specific Time in Gmail

Gmail supports an undocumented time-based search option that lets you find emails sent or received during a specific hour, minute or event second. For instance, you can limit your Gmail search to emails that were received between October 10 8:15 PM and October 10, 2020 8:45 PM.

Gmail Search Date and Time

To get started, convert the date and time to Epoch time and then use the timestamp with the standard after or before search operator of Gmail.

For instance, the Epoch time for October 10 8:30 PM is 1602774000 and that of October 10 8:45 PM is 1602774900. Use the search query after:1602774000 before:1602774900 to:me in Gmail and you’ll get a list of all emails that were received during that 15-minute period.

Epoch time is the number of seconds that have elapsed since January 1, 1970 (UTC). Use the Epoch converter to represent a human readable date and time in Epoch and use that timestamp with the before or after search operator of Gmail to find that elusive email.

Date and Time Search with Google Script

Here’s a little snippet that will automate your Gmail search by time using the Gmail API. It will fetch all email messages that were received between 12:15 PM and 1:30 PM.

const emailReceived = () => {
  const secondsSinceEpoch = (date) => Math.floor(date.getTime() / 1000);
  const after = new Date();
  const before = new Date();
  after.setHours(12, 15, 0, 0);
  before.setHours(13, 30, 0, 0);
  const query = `after:${secondsSinceEpoch(after)} before:${secondsSinceEpoch(
    before
  )}`;
  const messages = Gmail.Users.Messages.list('me', {
    q: query,
  });
  Logger.log(messages);
};

Also see: Mail Merge for Gmail

CSS in 3D: Learning to Think in Cubes Instead of Boxes

My path to learning CSS was a little unorthodox. I didn’t start as a front-end developer. I was a Java developer. In fact, my earliest recollections of CSS were picking colors for things in Visual Studio.

It wasn’t until later that I got to tackle and find my love for the front end. And exploring CSS came later. When it did, it was around the time CSS3 was taking off. 3D and animation were the cool kids on the block. They almost shaped my learning of CSS. They drew me in and shaped (pun intended) my understanding of CSS more than other things, like layout, color, etc.

What I’m getting at is I’ve been doing the whole 3D CSS thing a minute. And as with anything you spend a lot of time with, you end up refining your process over the years as you hone that skill. This article is a look at how I’m currently approaching 3D CSS and goes over some tips and tricks that might help you!

Everything’s a cuboid

For most things, we can use a cuboid. We can create more complex shapes, for sure but they usually take a little more consideration. Curves are particularly hard and there are some tricks for handling them (but more on that later).

We aren’t going to walk through how to make a cuboid in CSS. We can reference Ana Tudor’s post for that, or check out this screencast of me making one:

At its core, we use one element to wrap our cuboid and then transform six elements within. Each element acts as a side to our cuboid. It’s important that we apply transform-style: preserve-3d. And it’s not a bad idea to apply it everywhere. It’s likely we’ll deal with nested cuboids when things get more complex. Trying to debug a missing transform-style while hopping between browsers can be painful.

* { transform-style: preserve-3d; }

For your 3D creations that are more than a few faces, try and imagine the whole scene built from cuboids. For a real example, consider this demo of a 3D book. It’s four cuboids. One for each cover, one for the spine, and one for the pages. The use of background-image does the rest for us.

Setting a scene

We’re going to use cuboids like LEGO pieces. But, we can make our lives a little easier by setting a scene and creating a plane. That plane is where our creation will sit and makes it easier for us to rotate and move the whole creation.

For me, when I create a scene, I like to rotate it on the X and Y axis first. Then I lay it flat with rotateX(90deg). That way, when I want to add a new cuboid to the scene, I add it inside the plane element. Another thing I will do here is to set position: absolute on all cuboids.

.plane {
  transform: rotateX(calc(var(--rotate-x, -24) * 1deg)) rotateY(calc(var(--rotate-y, -24) * 1deg)) rotateX(90deg) translate3d(0, 0, 0);
}

Start with a boilerplate

Creating cuboids of various sizes and across a plane makes for a lot of repetition for each creation. For this reason, I use Pug to create my cuboids via a mixin. If you’re not familiar with Pug, I wrote a 5-minute intro.

A typical scene looks like this:

//- Front
//- Back
//- Right
//- Left
//- Top
//- Bottom
mixin cuboid(className)
  .cuboid(class=className)
    - let s = 0
    while s < 6
      .cuboid__side
      - s++
.scene
  //- Plane that all the 3D stuff sits on
  .plane
    +cuboid('first-cuboid')

As for the CSS. My cuboid class is currently looking like this:

.cuboid {
  // Defaults
  --width: 15;
  --height: 10;
  --depth: 4;
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform-style: preserve-3d;
  position: absolute;
  font-size: 1rem;
  transform: translate3d(0, 0, 5vmin);
}
.cuboid > div:nth-of-type(1) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
}
.cuboid > div:nth-of-type(2) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(180deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(3) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(4) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(-90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(5) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(6) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * -1vmin)) rotateX(180deg);
  position: absolute;
  top: 50%;
  left: 50%;
}

Which, by default, gives me something like this:

Powered by CSS variables

You may have noticed a fair few CSS variables (aka custom properties) in there. This is a big time-saver. I’m powering my cuboids with CSS variables.

  • --width: The width of a cuboid on the plane
  • --height: The height of a cuboid on the plane
  • --depth: The depth of a cuboid on the plane
  • --x: The X position on the plane
  • --y: The Y position on the plane

I use vmin mostly as my sizing unit to keep everything responsive. If I’m creating something to scale, I might create a responsive unit. We mentioned this technique in a previous article. Again, I lay the plane down flat. Now I can refer to my cuboids as having height, width, and depth. This demo shows how we can move a cuboid around the plane changing its dimensions.

Debugging with dat.GUI

You might have noticed that little panel in the top right for some of the demos we’ve covered. That’s dat.GUI. It’s a lightweight controller library for JavaScript that super useful for debugging 3D CSS. With not much code, we can set up a panel that allows us to change CSS variables at runtime. One thing I like to do is use the panel to rotate the plane on the X and Y-axis. That way, it’s possible to see how things are lining up or work on a part that you might not see at first.


const {
  dat: { GUI },
} = window
const CONTROLLER = new GUI()
const CONFIG = {
  'cuboid-height': 10,
  'cuboid-width': 10,
  'cuboid-depth': 10,
  x: 5,
  y: 5,
  z: 5,
  'rotate-cuboid-x': 0,
  'rotate-cuboid-y': 0,
  'rotate-cuboid-z': 0,
}
const UPDATE = () => {
  Object.entries(CONFIG).forEach(([key, value]) => {
    document.documentElement.style.setProperty(`--${key}`, value)
  })
}
const CUBOID_FOLDER = CONTROLLER.addFolder('Cuboid')
CUBOID_FOLDER.add(CONFIG, 'cuboid-height', 1, 20, 0.1)
  .name('Height (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'cuboid-width', 1, 20, 0.1)
  .name('Width (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'cuboid-depth', 1, 20, 0.1)
  .name('Depth (vmin)')
  .onChange(UPDATE)
// You have a choice at this point. Use x||y on the plane
// Or, use standard transform with vmin.
CUBOID_FOLDER.add(CONFIG, 'x', 0, 40, 0.1)
  .name('X (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'y', 0, 40, 0.1)
  .name('Y (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'z', -25, 25, 0.1)
  .name('Z (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-x', 0, 360, 1)
  .name('Rotate X (deg)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-y', 0, 360, 1)
  .name('Rotate Y (deg)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-z', 0, 360, 1)
  .name('Rotate Z (deg)')
  .onChange(UPDATE)
UPDATE()

If you watch the timelapse video in this tweet. You’ll notice that I rotate the plane a lot as I build up the scene.

That dat.GUI code is a little repetitive. We can create functions that will take a configuration and generate the controller. It takes a little tinkering to cater to your needs. I started playing with dynamically generated controllers in this demo.

Centering

You may have noticed that by default each cuboid is half under and half above the plane. That’s intentional. It’s also something I only recently started to do. Why? Because we want to use the containing element of our cuboids as the center of the cuboid. This makes animation easier. Especially, if we’re considering rotating around the Z-axis. I found this out when creating “CSS is Cake”. After making the cake, I then decided I wanted each slice to be interactive. I then had to go back and change my implementation to fix the rotation center of the flipping slice.

Here I’ve broken that demo down to show the centers and how having an offset center would affect the demo.

Positioning

If we are working with a scene that’s more complex, we may split it up into different sections. This is where the concept of sub-planes comes in handy. Consider this demo where I’ve recreated my personal workspace.

There’s quite a bit going on here and it’s hard to keep track of all the cuboids. For that, we can introduce sub-planes. Let’s break down that demo. The chair has its own sub-plane. This makes it easier to move it around the scene and rotate it — among other things — without affecting anything else. In fact, we can even spin the top without moving the feet!

Aesthetics

Once we’ve got a structure, it’s time to work on the aesthetics. This all depends on what you’re making. But you can get some quick wins from using certain techniques. I tend to start by making things “ugly” then go back and make CSS variables for all the colors and apply them. Three shades for a certain thing allows us to differentiate the sides of a cuboid visually. Consider this toaster example. Three shades cover the sides of the toaster:

https://codepen.io/jh3y/pen/KKVjLrx

Our Pug mixin from earlier allows us to define class names for a cuboid. Applying color to a side usually looks something like this:

/* The front face uses a linear-gradient to apply the shimmer effect */
.toaster__body > div:nth-of-type(1) {
  background: linear-gradient(120deg, transparent 10%, var(--shine) 10% 20%, transparent 20% 25%, var(--shine) 25% 30%, transparent 30%), var(--shade-one);
}
.toaster__body > div:nth-of-type(2) {
  background: var(--shade-one);
}
.toaster__body > div:nth-of-type(3),
.toaster__body > div:nth-of-type(4) {
  background: var(--shade-three);
}
.toaster__body > div:nth-of-type(5),
.toaster__body > div:nth-of-type(6) {
  background: var(--shade-two);
}

It’s a little tricky to include extra elements with our Pug mixin. But let’s not forget, every side to our cuboid offers two pseudo-elements. We can use these for various details. For example, the toaster slot and the slot for the handle on the side are pseudo-elements.

Another trick is to use background-image for adding details. For example, consider the 3D workspace. We can use background layers to create shading. We can use actual images to create textured surfaces. The flooring and the rug are a repeating background-image. In fact, using a pseudo-element for textures is great because then we can transform them if needed, like rotating a tiled image. I’ve also found that I get flickering in some cases working directly with a cuboid side.

One issue with using an image for texture is how we create different shades. We need shades to differentiate the different sides. That’s where the filter property can help. Applying a brightness``() filter to the different sides of a cuboid can lighten or darken them. Consider this CSS flipping table. All the surfaces are using a texture image. But to differentiate the sides, brightness filters are applied.

Smoke and mirrors perspective

How about shapes — or features we want to create that seem impossible — using a finite set of elements? Sometimes we can trick the eye with a little smoke and mirrors. We can provide a “faux” like sense of 3D. The Zdog library does this well and is a good example of this.

Consider this bundle of balloons. The strings holding them use the correct perspective and each has its own rotation, tilt, etc. But the balloons themselves are flat. If we rotate the plane, the balloons maintain the counter plane rotation. And this gives that “faux” 3D impression. Try out the demo and switch off the countering.

Sometimes it takes a little out-of-the-box thinking. I had a house plant suggested to me as I built the 3D workspace. I have a few in the room. My initial thought was, “No, I can make a square pot, and how would I make all the leaves?” Well actually, we can use some eye tricks on this one too. Grab a stock image of some leaves or a plant. Remove the background with a tool like remove.bg. Then position many images in the same spot but rotate them each a certain amount. Now, when they’re rotated, we get the impression of a 3D plant.

Tackling awkward shapes

Awkward shapes are tough to cover in a generic way. Every creation has its own hurdles. But, there is a couple of examples that could help give you ideas for tackling things. I recently read an article about the UX of LEGO interface panels. In fact, approaching 3D CSS work like it’s a LEGO set isn’t a bad idea. But the LEGO interface panel is a shape we could make with CSS (minus the studs — I only recently learned this is what they are called). It’s a cuboid to start with. Then we can clip the top face, make the end face transparent, and rotate a pseudo-element to join it up. We can use the pseudo-element for adding the details with some background layers. Try turning the wireframe on and off in the demo below. If we want the exact heights and angles for the faces, we can use some math to workout the hypoteneuse etc.

Another awkward thing to cover is curves. Spherical shapes are not in the CSS wheelhouse. We have various options at this point. One option is to embrace that fact and create polygons with a finite number of sides. Another is to create rounded shapes and use the rotation method we mentioned with the plant. Each of these options could work. But again, it’s on a use case basis. Each has pros and cons. With the polygon, we surrender the curves or use so many elements that we get an almost curve. The latter could result in performance issues. With the perspective trick, we may also end up with performance issues depending. We also surrender being able to style the “sides” of the shape as there aren’t any.

Z fighting

Last, but not least, it’s worth mentioning “Z-fighting.” This is where certain elements on a plane may overlap or cause an undesirable flicker. It’s hard to give good examples of this. There’s not a generic solution for it. It’s something to tackle on a case-by-case basis. The main strategy is to order things in the DOM as appropriate. But sometimes that’s not the only issue.

Being accurate can sometimes cause issues. Let’s refer to the 3D workspace again. Consider the canvas on the wall. The shadow is a pseudo-element. If we place the canvas exactly against the wall, we are going to hit issues. If we do that, the shadow and the wall are going to fight for the front position. To combat this, we can translate things by a slight amount. That will solve the issue and declare what should sit in front.

Try resizing this demo with the “Canvas offset” on and off. Notice how the shadow flickers when there is no offset? That’s because the shadow and the wall are fighting for view. The offset sets the --x to a fraction of 1vmin that we’ve named --cm. That’s a responsive unit being used for that creation.

That’s “it”!

Take your CSS to another dimension. Use some of my tips, create your own, share them, and share your 3D creations! Yes, making 3D things in CSS can be tough and is definitely a process that we can refine as we go along. Different approaches work for different people and patience is a required ingredient. I’m interested to see where you take your approach!

The most important thing? Have fun with it!


The post CSS in 3D: Learning to Think in Cubes Instead of Boxes appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Why Observability Is the Next Big Thing in Security

Observability for Application Security Is a Must-have

It's not easy to tell modern security stories to users of legacy security solutions still attached to squeezing some fading security value from network-based perimeter walls. Organizations and their application security teams still find it hard to justify the obvious need for true operational change in application development and deployment (cloud adoption sits at 46%), even as software — now in the form of complex, high-velocity, and distributed cloud architectures — continues to rapidly become the only known way to effectively grow a modern business.

Still, the fact is software developers and cross-functional teams will not wait and have simply taken application security away from SecOps because a new paradigm of observability for security purposes has emerged as a core requirement for effective protection of modern applications in the cloud. Today's complex, distributed, and ephemeral challenges brought forward by next-generation cloud adoption are the new critical roadblocks that enterprises must solve to achieve rapid business grow: either adopt a technology stack that delivers observability for security or lack the ability to effectively secure your cloud applications.