I've done this by storing the "toggle" variable to a file in /tmp. We can't use environment variables for the toggle, because each bindsym exec spawns a new shell and there's no way to set the environment variable in a parent process. In most distros, /tmp is tmpfs and stored in RAM, so it's still pretty fast to use.
Mod+= increases the "workspace modifier", adding 10 to every workspace number.
Mod+- decreases the "workspace modifier", subtracting 10 from every workspace number.
Normally, pressing Mod+1 will bring you to workspace 1. After pressing Mod+=, it will bring you to workspace 11.
Here's the config:
#Increase workspace modifier
bindsym $mod+equal exec echo $(( `cat /tmp/workspace_modifier` + 1 )) > /tmp/workspace_modifier
#Decrease workspace modifier
bindsym $mod+minus exec n=$(( `cat /tmp/workspace_modifier` - 1 )) && echo `[ $n -le 0 ] && echo '' || echo $n` > /tmp/workspace_modifier
#Switch to workspace
bindsym $mod+0 exec i3-msg workspace number `cat /tmp/workspace_modifier`0
bindsym $mod+1 exec i3-msg workspace number `cat /tmp/workspace_modifier`1
bindsym $mod+2 exec i3-msg workspace number `cat /tmp/workspace_modifier`2
bindsym $mod+3 exec i3-msg workspace number `cat /tmp/workspace_modifier`3
bindsym $mod+4 exec i3-msg workspace number `cat /tmp/workspace_modifier`4
bindsym $mod+5 exec i3-msg workspace number `cat /tmp/workspace_modifier`5
bindsym $mod+6 exec i3-msg workspace number `cat /tmp/workspace_modifier`6
bindsym $mod+7 exec i3-msg workspace number `cat /tmp/workspace_modifier`7
bindsym $mod+8 exec i3-msg workspace number `cat /tmp/workspace_modifier`8
bindsym $mod+9 exec i3-msg workspace number `cat /tmp/workspace_modifier`9
#Move focused container to workspace
bindsym $mod+Shift+0 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`0
bindsym $mod+Shift+1 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`1
bindsym $mod+Shift+2 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`2
bindsym $mod+Shift+3 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`3
bindsym $mod+Shift+4 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`4
bindsym $mod+Shift+5 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`5
bindsym $mod+Shift+6 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`6
bindsym $mod+Shift+7 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`7
bindsym $mod+Shift+8 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`8
bindsym $mod+Shift+9 exec i3-msg move container to workspace number `cat /tmp/workspace_modifier`9
Note that in this config, Mod+0 moves to workspace 0 instead of workspace 10. If this is important to you, you may wish to use these bindings:
bindsym $mod+0 exec n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` && i3-msg workspace number `echo "$w*10 + 10" | bc`
bindsym $mod+Shift+0 exec n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` && i3-msg move container to workspace number `echo "$w*10 + 10" | bc`
Keeping workspace names becomes very complicated because of the way i3 config handles variables: it does direct replacement instead of injecting them in the environment of exec commands, so it's not possible to retrieve the values dynamically without redeclaring them in the exec command. This quickly gets messy:
set $ws1 "1: one"
set $ws2 "2: two"
set $ws1 "11: eleven"
set $ws2 "12: twelve"
bindsym $mod+Shift+1 exec key=1 ws1=$ws1 ws2=$ws2 ws11=$ws11 ws12=$ws12 && i=`cat /tmp/workspace_modifier` && dynamic=ws${i}${key} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}${key}` ) && i3-msg move container to workspace number $workspace
This should works as long as in the exec command you only declare the workspaces that have been named using the set command. If, for example, you define set $ws1 "1: text" but do not set $ws11, then include ws11=$ws11 in the exec command, i3 config will expand ws11=$ws11 to ws11="1: one"1 because it matches $ws1 in $ws11. It works fine otherwise.
If you wish to use workspace names plus keep Mod+0 set to workspace 10, use these bindsyms:
bindsym $mod+0 exec key=0 ws1=$ws1 ws2=$ws2 ws3=$ws3 ws4=$ws4 ws5=$ws5 ws6=$ws6 ws7=$ws7 ws8=$ws8 ws9=$ws9 ws10=$ws10 && n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` i=`echo "$w*10 + 10" | bc` && dynamic=ws${i} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}` ) && i3-msg workspace number $workspace
bindsym $mod+Shift+0 exec key=0 ws0=$ws0 ws1=$ws1 ws2=$ws2 ws3=$ws3 ws4=$ws4 ws5=$ws5 ws6=$ws6 ws7=$ws7 ws8=$ws8 ws9=$ws9 ws10=$ws10 && n=`cat /tmp/workspace_modifier` w=`[ $n ] && echo $n || echo 0` i=`echo "$w*10 + 10" | bc` && dynamic=ws${i} && text=${!dynamic} && workspace=$(echo `[ "$text" ] && echo "$text" || echo ${i}` ) && i3-msg move container to workspace number "$workspace"