Markdown is a convenient HTML-focused shorthand syntax for formatting content such as documentation and blog articles, but it lacks basic features for image formatting, such as alignment and sizing.This post presents a variety of ways to format images with Markdown, from brute force to proprietary syntax extensions, unwise hacks, and everything in between.
Bitbucket does not support so you need to use the - (dash) and the (pipe) symbols to construct a table. The first line contains column headers. Separate columns with the pipe symbol. The second line must be a mandatory separator line between the headers and the content. Bitbucket can parse and display Markdown, reStructuredText, Textile, and plain text README files. With a syntax like Markdown, you can emphasize text, include screen captures, and more. For a tutorial on Bitbucket's Markdown support and syntax examples, see our Markdown demo repository.
I'm using Bitbucket API (2.0) to submit comments to Pull Rrequests but I'm having a hard time figuring out how to send 'styled' comments either using Markdown or HTML. I've only managed to send comments in raw mode so far.
Here’s how you insert an image in Markdown:
That is, Markdown allows you to specify an <img>
tag with src
, alt
, and title
attributes in HTML.Standard Markdown doesn’t offer anything beyond this, but it’s very common for websites to need width
, height
, and CSS class
attributes as well.
The rest of this post is dedicated to various solutions to these shortcomings.To motivate this discussion, I’ll use the example of a large image that should be displayed at a smaller size.
For example,
I won’t show you how to add alignment, floating, or padding—but my sizing example will suffice, because once you know how to change an image’s size, you’ll know how to do other things too.I’ll show you the best solutions first, and the undesirable ones last.
Use Standard HTML
Markdown was originally designed for HTML authoring, and permits raw HTML anywhere, anytime.As such, the most straightforward solution is simply to use HTML with the desired attributes:
This works, and gives you unrestrained control over the resulting HTML.But Markdown is appealing for its simplicity, unlike HTML that’s cluttered with messy markup.Thus, many people dislike this solution because it defeats the purpose of Markdown.
Use CSS And Special URL Parameters
In general, the best way to style images is with CSS.Modern CSS syntax can select elements based on the values of their attributes, so one way to apply CSS rules is to encode extra information into Markdown’s standard src
attribute.In this section I’ll discuss these possibilities.Later I’ll show you some undesirable CSS-related techniques too.
There are two places in a URL that you can overload to carry information that CSS can use: the URL fragment, and URL query parameters.
The URL fragment is the part that comes after the #
character.When it’s used in a website’s URL, it can scroll the page to bring a desired part of the content into view, but you can add it to images, too.When you do that, it essentially does nothing as far as the browser is concerned, and a typical user will never see it in the browser’s address bar either.But it’s useful for our styling needs.Here we’ll add a thumbnail
fragment to the image’s source URL:
This information is kept entirely client-side, and browsers don’t transmit this part of the URL to the server when they request content.However, CSS and JavaScript can read the fragment and use it.Here’s how to write a CSS selector that will match images with this “thumbnail” information in the URL:
The *=
selector syntax matches if #thumbnail
appears anywhere in the src
attribute.You could also anchor the matching to the end of the URL with $='#thumbnail'
.
This permits encoding only a single value into the URL, but you can modify this technique to add several.CSS also has a ~=
selector, which matches if the specified value appears exactly in the attribute’s value, as a space-delimited “word,” so to speak.This lets you simulate combining multiple “classes” in the URL fragment:
Now you can target these pseudo “class” names from CSS:
An equivalent way to encode a space into a URL is with the %20
URL encoding, but I’ve found that this doesn’t work1 in the Blackfriday Markdown processor with the technique I showed here:
Naturally, you can pick different ways to structure values, such as using a key=value
syntax or whatever suits your purposes.Depending on what you prefer, you can use any of the CSS selector syntaxes that works well for you.
Another alternative is to use ordinary URL query parameters, the part that comes after the question-mark:
This will work, and you can use the same types of CSS selectors to apply styling to the resulting image.
However, in my opinion this is slightly less desirable, because query parameters are meant to transmit information to the server.The browser will include the parameters in the request, and there could be other disadvantages, such as preventing the browser from caching the images for better performance.Overall I don’t see any advantages to query parameters, unless there’s some reason you can’t use the URL fragment.
Use CSS’s nth-child() Selectors
You can also use CSS selectors that will select images based on their position in the document.For example, if your blog’s main content is wrapped inside an article
element, and you want to change the appearance of the image inside the third paragraph, you could write the following CSS:
This will work, but it’s tedious and requires article-specific <style>
tags with custom CSS.And you’ll need to change the CSS if you change the article, for example adding another paragraph above the image.In general this technique will be a burden to maintain, and I don’t do it.
To learn more about this, take a look at the CSS nth-of-type and nth-child selectors.
Use Proprietary Markdown Extensions
The original Markdown spec isn’t formal, and implementations vary.Many Markdown processors extend the syntax to add richness and control to the output.From Pandoc to Kramdown and Github-Flavored Markdown (GFM), extra syntaxes abound.There’s very little standardization, except for some consensus towards CommonMark and the gravitational pull of very popular libraries and processors.In this section I’ll explore some of these.
Some Markdown editors like Mou (a Mac writing app) have sizing extensions:
This example syntax is limited and isn’t widely supported.More common is the way Kramdown offers extensions to add attributes to block-level elements, including not only the height and width but CSS and other attributes:
Kramdown also supports one or more CSS classes with a shorthand syntax.Here’s an example of how to add class='thumbnail bordered'
to the HTML after processing with Kramdown:
Pandoc offers a relative width specification, which works not only for HTML output, but for other output formats such as ( LaTeX ) as well:
Some other Markdown flavors offer similar ways to add attributes, though the syntax may differ slightly.All of these, however, extend the basic Markdown syntax in ways that may be incompatible.And some rumored support for extended syntax simply doesn’t exist; for example, I’ve seen references to nonexistent extensions in the blackfriday Markdown processor, which Hugo uses.
Use Wrapper HTML Tags
Another technique is to put an HTML tag around the <img>
tag, like this:
Unfortunately, standard Markdown doesn’t process and convert the text inside of tags such as the <div>
; as soon as it sees raw HTML it simply outputs it verbatim until the tags are closed again.This approach will work only with processors that support Markdown syntax extensions such as Markdown Extra.In Hugo, using Blackfriday, the resulting output is simply
Use Processor Hacks That Markdown Editors Ignore
Some users like to edit in a WYSIWYG editor such as Mou, but use a system such as Hugo to render the final Markdown into HTML for publication.Hugo has special processors that can add features to the output, such as brace-delimited shortcodes, which Mou doesn’t understand.
You can take advantage of this to inject content that overflows the alt
attribute.The trick is to make the shortcode output an extra closing quote at the beginning of its output, emit the desired HTML attributes but omit the closing quote, and let the Markdown processor supply that.The benefit is that your editor will ignore the markup it doesn’t recognize, so it doesn’t disrupt your editing workflow.I don’t think this is better than the alternatives myself, but I mention it for completeness.
Abuse Image Attributes As CSS Selector Targets
In addition to the URL fragment as discussed previously, modern CSS syntax can select values of the alt
and title
attributes that standard Markdown supports.In this section I’ll discuss each of these possibilities, although I discourage their use.
Many Markdown users are only aware of the standard syntax’s support for the alt
attribute, and don’t add titles to their images.In fact, many don’t even add alt text:
This makes it seem as though the alt text is undeveloped real estate that could be repurposed, for example adding the pseudo-equivalent of a “thumbnail” CSS class.Here’s how you might attempt to do that:
The corresponding CSS to select and format this image could be
Technically, this will work, but it’s not good for accessibility.Users who are using a screen reader or other accessibility aid will gain no benefit, and will suffer due to the lack of helpful information and the presence of misleading data in places it’s not intended to be.I discourage this practice.
A variation I’ve seen is to append, rather than replace, the alt text, using syntaxes such as the following examples:
Those examples can be paired with a CSS selector that matches the end of the attribute, such as img[alt$='-thumbnail']
.These are perhaps less offensive than replacing the alt text entirely, but I still discourage this because there are better ways.
A variant of this approach, which has a roughly equivalent impact on accessibility, is to overload the title
attribute with formatting instructions:
This can be selected from CSS as follows:
Again, I want to emphasize that this approach is not better than misusing the alt
attribute.You should use URL fragments or URL query parameters as discussed earlier, instead of hijacking the image’s alt text or title.
On the other hand, if you want to write custom CSS per-article and use the CSS selector to target the image’s real alt text or title, that’s perfectly fine.In fact this is probably easier to maintain than nth-child
selectors:
The demos in this page use the actual markup in the code listings. You can viewthe page source or look at the file in my Github repoto see the original markup in HTML and/or Markdown formats.
- Thanks to a reader who pointed out that Markdown implementations vary widely in how they encode or interpret spaces. The technique as shown in this article doesn’t work with Grav, which needs spaces encoded as
%20
. This thread on StackOverflow has more information. [return]
Introduction to Git
In this tutorial, we will learn about Git, a tool for version control.
Administrative Note
Even if you've used git before, I request that you use this tutorial. I will expect your solution to phase 0 to have the file structure and initial commit history that would be produced from this tutorial.
Required Software For This Tutorial
All of the software listed below is going to be used during this course, so you might as well install these programs now.
- Git
- If you are using windows, you should use Git Bash for Windows
- A terminal
- If you are working in windows, Git Bash for Windows will do the job. On Mac and Linux, you should already have a terminal installed
- Visual Studio Code
- VSCode is a lightweight environment for writing code.
The Big Picture
Git can be confusing at first, because it plays three very important, but somewhat separate roles:
- It lets you checkpoint your work, by committing different versions of your code. At any time, you can restore any checkpoint to see exactly what your code looked like at any point in time. Checkpoints also let you see how your current code has changed relative to the most recent commit, and let you undo mistakes quickly and easily.
- When used with a service provider, such as Bitbucket or GitHub, git provides remote storage for all of the versions of your code, so that you don't lose your work if you accidentally delete your local copy. This also makes it easy to share your code with others: they can get the latest version from Bitbucket.
- When you work in a team, git provides powerful branching and merging features, so that people can work separately, and then combine their work. If teammates overwrite each others' work, git will let you know, and help you to get things to work. However, you shouldn't just rely on git... good habits will help you to avoid merge conflicts, and keep your development on track.
A Few Examples
To appreciate the power of git, let's consider a few usage scenarios:
- The Lone Developer
- Evelyn is trying to add OAuth-based login to her program. She's not sure which OAuth flow makes the most sense, but she thinks 'implicit grant flow' would be best. She creates a new 'local branch' of her repository. She works in that local branch, committing every time she has made progress. Suppose that after 3 days, and 25 commits, she has it all working... she'd merge her branch back into the main repository, to make it official. On the other hand, if after all that time, she can't get it to work, she simply switches back to the main branch, and all of the old working code is still there.
- The Pair Programmers
- Ryan and Hannah are working together on a project. They each can make changes, commit them, and push those changes to Bitbucket. To get Hannah's work, Ryan can pull it into his local copy, and vice versa. Even though they are working on the exact same files, they can use git to coordinate their efforts. At all times, the version on Bitbucket is sure to work, even if Hannah and Ryan each have dirty checkouts with some incomplete new features.
- The Compartmentalized Team
- Bill, Faith, and Andi are working on the back-end, front-end, and Android parts of their program. They each work in a branch, but now the branches are visible to Bitbucket. Their project manager, Pat, can merge each teammate's code into the master branch, and only does so after a proper code review.
- The Decentralized Team
- Different organizations are contributing to the same code base, and one of them owns the 'master' repository. Other organizations begin by creating 'forks' of the master repository, and operating as a team within a fork. From time to time, they submit a 'pull request' to ask the owner of the master branch to incorporate a set of changes that they have made, so that those changes can be available to everyone who works with master. Also, any time master changes, the fork owner can pull those changes from master.
In this class, we will primarily work as a compartmentalized team. For this individual project, you will emulate the behavior of a compartmentalized team by working on multiple branches, and merging them together.
Getting Started
Bitbucket Markdown Editor Download
In the real world, your first step would be to create a repository. However, in this class I will always provide a repository for you. Thus, you will want to get a 'clone' of the repository I made for you. Its name is based on your Lehigh userid. My userid is 'mfs409', so my repository is named https://mspear@bitbucket.org/mspear/cse216_mfs409.git. To get it, I should go to the folder that I want to be the parent of the folder where I will do my work, and then type git clone https://mspear@bitbucket.org/mspear/cse216_mfs409.git. Here's an example, using Git Bash for Windows:
Let's break down what just happened:
- I typed 'cd Desktop' to go into my Desktop folder
- I used the 'git clone' command to get a copy of the repository where I'm supposed to do my work. (Note: you'll need to provide a password... I didn't show that part!)
- I used the 'cd' command again, to move into the folder I just created.
- I used the 'ls' command to see what files were in the folder.
- I used 'ls -a' to see all files, even the hidden ones.
Note: you should never do anything in the '.git' folder. It's there for git to use.
Next, let's open this file in Visual Studio Code. From the terminal, type 'code . &' to open up the current folder. Then on the left, choose README.md. Then on the right, click the button to 'Open Preview to the Side'. You should see something like this:
To understand what's going on here, it is useful to take a look at the home page for your project on Bitbucket. Mine is at https://bitbucket.org/mspear/cse216_mfs409... if you click that link, you won't have permission to view the page, but if you change the 'mfs409' to your username, you should see your page... and it will look something like this:
The 'README.md' file is written in a language called 'markdown'. Markdown is a lightweight language that can easily be translated to HTML. Bitbucket is translating our README.md file into HTML and embedding it into the main page for our repository. Pretty cool!
For more information about markdown, visit https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet.
Our First Commit
In Visual Studio Code, we're going to make a small change to our README.md file. Add the following lines to the end (note: you should use your name, not mine!):
Now let's go back to the terminal and take a look at the root folder of our repository:
I typed 'git status', and now git is informing me that I have made changes to one file. Let's see exactly what changed, by typing 'git diff':
In this case, I know that these are the changes that I intended to make. I want to permanently add them to the repository, so I will do three things. First, I will 'stage' my changes for commit. All that means is that I will tell git that I'm putting together the next snapshot of my repository, and I want these changes to README.md to be part of that snapshot. I can do that with the 'git add' command:
Notice that 'git status' now tells me that my changes to README.md are staged, and ready to commit. When I commit, I need to provide a message to accompany the commit. I do this via the 'git commit' command. Use the '-m' parameter to provide a message to describe your commit:
So far, so good. But if I go to the 'Commits' page on Bitbucket, my changes won't appear yet:
The problem here is that I've made a snapshot on my local computer, but I haven't sent it to Bitbucket yet. There are reasons why it's very good for these two steps to be separate, even though it seems confusing at first. Among other things, it means that you can make lots of snapshots, even while you're breaking things and experimenting. Then, when you finally have it all working, you can send it all to Bitbucket.
Let's send the code to Bitbucket, via 'git push':
When I refresh the 'Commits' listing, I'll see that my commit is at the top of the list:
Be sure to click on the blue commit identifier, to see how the web interface can show exactly what changed on account of the commit you pushed.
Working with Branches
Ultimately, we are going to want to work on a program that has four distinct parts:
- A back-end Java server
- A web front-end that accesses the server
- An Android app that accesses the server
- A command-line Java program for running administrative tasks
We're going to have four people working on these at any time. Right now all of our code is in the default branch, called 'master'. Git will make it easy for our four developers, working on their four different parts, to do so in four different 'branches'. Each branch will be isolated from the others: you can 'commit' to your branch as often as you like, and even 'push', and none of the other branches will be affected. Then, when another branch needs your code, that branch can 'merge' your work into it.
It is possible to have local branches that Bitbucket doesn't know about, but we won't do that in this tutorial. Thus, we will use the Bitbucket web interface to create our branches. We'll make four branches, called 'admin', 'android', 'backend', and 'web'. We can make them by choosing the 'Branches' view, and then clicking 'Create branch':
Once you've made all four branches, it's time to start working with them. Head on over to the command line and type 'git fetch'. It will look like nothing happened. But then try checking out the 'web' branch:
If you run the 'ls' command, it will look like nothing has changed. But the '(web)' message in the command prompt is showing us that we are not in the 'master' branch anymore. Let's make a folder, put another README.md file into it, and stage it for commit:
(Note: that 'echo ...' line is saying 'print the following text to the screen', and then '>> README.md' indicates that we want the text to go to README.md instead of to the screen.)
Now let's commit the changes:
If we visit the 'Branches' page on Bitbucket, our 'web' branch will now appear:
Our changes are in the 'web' branch, but they are not in the 'master' branch. To convince ourselves of that, we can look at the 'Source' view in Bitbucket. Here's the source view for 'master'... notice there is no 'web' folder:
But we can click on 'master' in the pulldown, and select 'web' instead:
Now the source listing shows that there's a new folder that is part of the 'web' source tree:
If we click on it, we'll see that the web folder has its own README.md:
Let's go ahead and bring this commit into the 'master' branch. We will use 'git merge' to do it, and when we do, we will merge an entire branch. The branch won't go away, but all of its changes will be merged into master. Let's try it. We need to switch back to the master branch, and then merge the web branch into it. Then we can push the changes to master back to Bitbucket.
That was easy, but only because (1) this is a tutorial, and (2) we're carefully partitioning our work. Since we even pushed already, we should be able to see the code on the Bitbucket website when looking at master:
The web folder is there! If we look inside of it, we'll see that the README.md file is there, too.
Setting Up Our Other Branches
Using the command line, we can quickly do the same in the admin branch:
Next, let's do the android branch:
And, of course, the backend branch:
We didn't push anything yet... let's go back through these branches and push them all:
Finally, let's switch to the 'master' branch, and merge the branches into it. Type 'git checkout master' and then 'git merge admin'. We're going to get a strange screen:
When we try to merge here, git wants us to provide a commit message. It has assumed that we want the message to be 'Merge branch 'admin'. That's good enough for now, especially since it is using the 'vi' editor to enter the message, which you may not be familiar with. To save the file, press the escape key 3 times. Then type ':wq'. You should see 'vi' exit, and the merge complete:
We learned our lesson here: always provide a '-m' parameter whenever committing or merging. Let's merge our other two branches:
Finally, issue a 'git push' command to send all of these new changes back to Bitbucket. When you visit the 'Commits' view and choose the 'master' branch, you'll be in for a surprise. Since our branches' commits all happened before we merged anything into 'master', the listing shows how there were divergent versions of the repository, which were all merged back into 'master'.
More importantly, when we look at the 'Source' view, we will see that all of our folders are part of 'master':
Wrapping Up
Believe it or not, we've only scratched the surface of what git can do. There are some important commands we haven't seen yet:
- git mv ...
- git rm ...
- git pull
- git log
- git reset HEAD ...
- git checkout -- ...
We'll get to them in later tutorials. At this point, make sure you are in a nice clean state by using 'git checkout master' to be sure you are in your 'master' branch. Then you can type 'exit' to close your command prompt, and close Visual Studio Code... for now, we're all done.
Comments are closed.