Canada’s Top 25 Best Places to Live in 2018


.WB18{
box-sizing:border-box
}
.WB18 *{
box-sizing:inherit
}
.WB18 a{
transition-property:background-color,color;
transition-duration:.2s
}
.grid>div{
float:left
}
.grid{
display:flex;
flex-direction:column
}
.font__display–proxima{
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif
}
.font__display–jubilat{
font-family:jubilat,Georgia,serif
}
.WB18 h1,.WB18 h2,.WB18 h3,.WB18 h4,.WB18 h5,.WB18 h6{
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif;
font-weight:900
}
.WB18__header–wrap{
/*margin-bottom:2em */
}
.WB18__header{
display:block;
padding: 0;
text-align:center;
background-color:#2fbcf2;
color:#fff;
background-position:center center;
font-family:jubilat,Georgia,serif;
cursor:pointer
}
.WB18__header:hover{
color:#afeeee;
background-color:#29c4f2
}
.WB18__header span{
display:inline-block;
color:#dc1b1b;
transition-property:color;
transition-duration:.2s
}
.WB18__header span.to-animate{
animation-name:tada;
animation-duration:.9s;
animation-delay:1s
}
.WB18__header:hover span{
color:#dc143c
}
.WB18__header:hover span.label__year{
color:#444
}
.WB18__desktop {
display: none;
}
@media (min-width:768px){
.grid{
flex-direction:row
}
.grid>*{
padding-left:1em;
padding-right:1em;
flex-grow:1
}
.grid>:first-child{
margin-left:0
}
.grid>:last-child{
margin-right:0
}
.block{
width:100%
}
.WB18__header{
padding:0;
}
}
.WB18__headline,.single-post article h1.WB18__headline{
color:#fff
}
.WB18__header .label__year{
display:block;
position:absolute;
line-height:1em;
padding:.3em .8em .2em;
top:.25em;
right:.25em;
background-color:gold;
color:#444;
font-weight:900;
box-shadow:2px 2px 6px rgba(0,0,0,.5);
border-radius:20%/50%
}
.WB18__nav{
display:flex;
flex-wrap:wrap;
flex-direction:column;
margin:0;
background-color:#eee
}
@media (min-width:768px){
.WB18__header .label__year{
font-size:1.4em;
right:-.25em
}
.WB18__nav{
flex-direction:row;
justify-content:stretch
}
.WB18__nav a,.WB18__nav button{
/* flex-grow:1 */
flex-basis: 50%;
}
}
@media (min-width: 1264px){
.WB18__nav a,.WB18__nav button{
/* flex-grow:1 */
flex-basis: 25%;
}
}
.WB18__nav a,.WB18__nav button{
padding:1rem 0.8rem;
border:0;
text-align:left;
background-color:#eee;
color:#dc1b1b;
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif
}
#WB18__nav–togglerOne.active,#WB18__nav–togglerTwo.active,.WB18__nav a:hover,.WB18__nav button:hover{
background-color:#29c4f2;
color:#fff
}
.WB18__nav–overview{
order:1
}
.WB18__nav–other{
order:2
}
#WB18__nav–togglerOne{
order:3
}
#WB18__nav–togglerTwo{
order:4
}
.WB18__nav button{
outline:0
}
.WB18__nav #WB18__nav–togglerOne,.WB18__nav #WB18__nav–togglerTwo{
position:relative;
z-index:20
}
.WB18__nav #WB18__nav–togglerOne::after,.WB18__nav #WB18__nav–togglerTwo::after{
display:inline-block;
padding:0 1rem;
content:’ 025BE’;
transition-property:transform;
transition-duration:.2s
}
.WB18__nav #WB18__nav–togglerOne.active::after,.WB18__nav #WB18__nav–togglerTwo.active::after{
content:’ 025BE’;
transform:rotate(180deg)
}
.WB18__nav–citylistOne,.WB18__nav–citylistTwo{
position:absolute;
display:flex;
width:100%;
z-index:10;
flex-direction:column;
transform:translateX(-999em);
box-shadow:0 6px 4px rgba(0,0,0,.5)
}
.WB18__nav–citylistOne.active,.WB18__nav–citylistTwo.active{
transform:translateX(0);
z-index:20
}
.WB18__nav–citylistOne a,.WB18__nav–citylistTwo a{
background-color:#29c4f2;
color:#eee
}
.WB18__nav–citylistOne a:hover,.WB18__nav–citylistTwo a:hover{
background-color:#444;
color:#eee
}
@media (min-width:768px){
.WB18__nav–overview{
order:1
}
.WB18__nav–other{
order:4
}
#WB18__nav–togglerOne{
order:2
}
#WB18__nav–togglerTwo{
order:3
}
.WB18__mobile {
display: none;
}
.WB18__desktop {
display: block;
}
}
@keyframes tada{
from,to{
–transform:scale3d(1,1,1);
transform:scale3d(1,1,1)
}
10%,20%{
–transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);
transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)
}
30%,50%,70%,90%{
–transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);
transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)
}
40%,60%,80%{
–transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);
transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)
}
}

! function(e, t) { “object” == typeof exports && “object” == typeof module ? module.exports = t() : “function” == typeof define && define.amd ? define([], t) : “object” == typeof exports ? exports.inView = t() : e.inView = t() }(this, function() { return function(e) { function t(i) { if (n[i]) return n[i].exports; var r = n[i] = { exports: {}, id: i, loaded: !1 }; return e[i].call(r.exports, r, r.exports, t), r.loaded = !0, r.exports } var n = {}; return t.m = e, t.c = n, t.p = “”, t(0) }([function(e, t, n) { “use strict”; var i, r = n(2), o = (i = r) && i.__esModule ? i : { default: i }; e.exports = o.default }, function(e, t) { e.exports = function(e) { var t = typeof e; return null != e && (“object” == t || “function” == t) } }, function(e, t, n) { “use strict”; function i(e) { return e && e.__esModule ? e : { default: e } } Object.defineProperty(t, “__esModule”, { value: !0 }); var r = i(n(9)), o = i(n(3)), u = n(4); t.default = function() { if (“undefined” != typeof window) { var e = { history: [] }, t = { offset: {}, threshold: 0, test: u.inViewport }, n = (0, r.default)(function() { e.history.forEach(function(t) { e[t].check() }) }, 100); [“scroll”, “resize”, “load”].forEach(function(e) { return addEventListener(e, n) }), window.MutationObserver && addEventListener(“DOMContentLoaded”, function() { new MutationObserver(n).observe(document.body, { attributes: !0, childList: !0, subtree: !0 }) }); var i = function(n) { if (“string” == typeof n) { var i = [].slice.call(document.querySelectorAll(n)); return e.history.indexOf(n) > -1 ? e[n].elements = i : (e[n] = (0, o.default)(i, t), e.history.push(n)), e[n] } }; return i.offset = function(e) { if (void 0 === e) return t.offset; var n = function(e) { return “number” == typeof e }; return [“top”, “right”, “bottom”, “left”].forEach(n(e) ? function(n) { return t.offset[n] = e } : function(i) { return n(e[i]) ? t.offset[i] = e[i] : null }), t.offset }, i.threshold = function(e) { return “number” == typeof e && e >= 0 && e <= 1 ? t.threshold = e : t.threshold }, i.test = function(e) { return "function" == typeof e ? t.test = e : t.test }, i.is = function(e) { return t.test(e, t) }, i.offset(0), i } }() }, function(e, t) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var n = function() { function e(e, t) { for (var n = 0; n -1, o = !n && r; n && !r && (e.current.push(t), e.emit(“enter”, t)), o && (e.current.splice(i, 1), e.emit(“exit”, t)) }), this } }, { key: “on”, value: function(e, t) { return this.handlers[e].push(t), this } }, { key: “once”, value: function(e, t) { return this.singles[e].unshift(t), this } }, { key: “emit”, value: function(e, t) { for (; this.singles[e].length;) this.singles[e].pop()(t); for (var n = this.handlers[e].length; –n > -1;) this.handlers[e][n](t); return this } }]), e }(); t.default = function(e, t) { return new i(e, t) } }, function(e, t) { “use strict”; Object.defineProperty(t, “__esModule”, { value: !0 }), t.inViewport = function(e, t) { var n = e.getBoundingClientRect(), i = n.top, r = n.right, o = n.bottom, u = n.left, c = n.width, s = n.height, f = o, a = window.innerWidth – u, l = window.innerHeight – i, d = r, p = t.threshold * c, h = t.threshold * s; return f > t.offset.top + h && a > t.offset.right + p && l > t.offset.bottom + h && d > t.offset.left + p } }, function(e, t) { (function(t) { var n = “object” == typeof t && t && t.Object === Object && t; e.exports = n }).call(t, function() { return this }()) }, function(e, t, n) { var i = n(5), r = “object” == typeof self && self && self.Object === Object && self, o = i || r || Function(“return this”)(); e.exports = o }, function(e, t, n) { var i = n(1), r = n(8), o = n(10), u = “Expected a function”, c = Math.max, s = Math.min; e.exports = function(e, t, n) { function f(t) { var n = h, i = v; return h = v = void 0, w = t, m = e.apply(i, n) } function a(e) { var n = e – b; return void 0 === b || n >= t || n = y } function l() { var e, n, i = r(); return a(i) ? d(i) : void(g = setTimeout(l, (e = i, n = t – (e – b), x ? s(n, y – (e – w)) : n))) } function d(e) { return g = void 0, T && h ? f(e) : (h = v = void 0, m) } function p() { var e, n = r(), i = a(n); if (h = arguments, v = this, b = n, i) { if (void 0 === g) return e = b, w = e, g = setTimeout(l, t), O ? f(e) : m; if (x) return g = setTimeout(l, t), f(b) } return void 0 === g && (g = setTimeout(l, t)), m } var h, v, y, m, g, b, w = 0, O = !1, x = !1, T = !0; if (“function” != typeof e) throw new TypeError(u); return t = o(t) || 0, i(n) && (O = !!n.leading, y = (x = “maxWait” in n) ? c(o(n.maxWait) || 0, t) : y, T = “trailing” in n ? !!n.trailing : T), p.cancel = function() { void 0 !== g && clearTimeout(g), w = 0, h = b = v = g = void 0 }, p.flush = function() { return void 0 === g ? m : d(r()) }, p } }, function(e, t, n) { var i = n(6); e.exports = function() { return i.Date.now() } }, function(e, t, n) { var i = n(7), r = n(1), o = “Expected a function”; e.exports = function(e, t, n) { var u = !0, c = !0; if (“function” != typeof e) throw new TypeError(o); return r(n) && (u = “leading” in n ? !!n.leading : u, c = “trailing” in n ? !!n.trailing : c), i(e, t, { leading: u, maxWait: t, trailing: c }) } }, function(e, t) { e.exports = function(e) { return e } }]) }), function(e, t) { if (“function” == typeof define && define.amd) define([“module”, “exports”], t); else if (“undefined” != typeof exports) t(module, exports); else { var n = { exports: {} }; t(n, n.exports), e.fitty = n.exports } }(this, function(e, t) { “use strict”; Object.defineProperty(t, “__esModule”, { value: !0 }); var n = Object.assign || function(e) { for (var t = 1; t 1 && void 0 !== arguments[1] ? arguments[1] : {}; return “string” == typeof e ? t(r(document.querySelectorAll(e)), n) : t([e], n)[0] } if (e) { var r = function(e) { return [].slice.call(e) }, o = { IDLE: 0, DIRTY_CONTENT: 1, DIRTY_LAYOUT: 2, DIRTY: 3 }, u = [], c = null, s = “requestAnimationFrame” in e ? function() { e.cancelAnimationFrame(c), c = e.requestAnimationFrame(function() { a(u.filter(function(e) { return e.dirty })) }) } : function() {}, f = function(e) { return function() { u.forEach(function(t) { t.dirty = e }), s() } }, a = function(e) { e.filter(function(e) { return !e.styleComputed }).forEach(function(e) { e.styleComputed = p(e) }), e.filter(h).forEach(y), e.filter(d).forEach(l), e.forEach(v), e.forEach(m) }, l = function(e) { e.availableWidth = e.element.parentNode.clientWidth, e.currentWidth = e.element.scrollWidth, e.previousFontSize = e.currentFontSize, e.currentFontSize = Math.min(Math.max(e.minSize, e.availableWidth / e.currentWidth * e.previousFontSize), e.maxSize), e.whiteSpace = e.multiLine && e.currentFontSize === e.minSize ? “normal” : “nowrap” }, d = function(e) { return e.dirty !== o.DIRTY_LAYOUT || e.dirty === o.DIRTY_LAYOUT && e.element.parentNode.clientWidth !== e.availableWidth }, p = function(t) { var n = e.getComputedStyle(t.element, null); t.currentFontSize = parseInt(n.getPropertyValue(“font-size”), 10), t.display = n.getPropertyValue(“display”), t.whiteSpace = n.getPropertyValue(“white-space”) }, h = function(e) { var t = !1; return /inline-/.test(e.display) || (t = !0, e.display = “inline-block”), “nowrap” !== e.whiteSpace && (t = !0, e.whiteSpace = “nowrap”), t }, v = function(e) { y(e), e.dirty = o.IDLE }, y = function(e) { e.originalStyle || (e.originalStyle = e.element.getAttribute(“style”) || “”), e.element.style.cssText = e.originalStyle + “;white-space:” + e.whiteSpace + “;display:” + e.display + “;font-size:” + e.currentFontSize + “px” }, m = function(e) { e.element.dispatchEvent(new CustomEvent(“fit”, { detail: { oldValue: e.previousFontSize, newValue: e.currentFontSize, scaleFactor: e.currentFontSize / e.previousFontSize } })) }, g = function(e, t) { return function() { e.dirty = t, s() } }, b = function(e) { e.newbie = !0, e.dirty = !0, u.push(e) }, w = function(e) { return function() { u = u.filter(function(t) { return t.element !== e.element }), e.observeMutations && e.observer.disconnect(), e.element.style.cssText = e.originalStyle } }, O = function(e) { e.observeMutations && (e.observer = new MutationObserver(g(e, o.DIRTY_CONTENT)), e.observer.observe(e.element, e.observeMutations)) }, x = { minSize: 16, maxSize: 512, multiLine: !0, observeMutations: “MutationObserver” in e && { subtree: !0, childList: !0, characterData: !0 } }, T = null, L = function() { e.clearTimeout(T), T = e.setTimeout(f(o.DIRTY_LAYOUT), i.observeWindowDelay) }, S = [“resize”, “orientationchange”]; return Object.defineProperty(i, “observeWindow”, { set: function(t) { var n = (t ? “add” : “remove”) + “EventListener”; S.forEach(function(t) { e[n](t, L) }) } }), i.observeWindow = !0, i.observeWindowDelay = 100, i.fitAll = f(o.DIRTY), i } }(“undefined” == typeof window ? null : window), e.exports = t.default }), fitty(“.fit”), inView(“.fit”).on(“enter”, function() { fitty(“.fit”) }), function(e) { function t() { if (this.id === “WB18__nav–togglerOne”) { !1 === e.cityListOneOpen ? e.cityListOneOpen = !0 : e.cityListOneOpen = !1, e.togglerOne.classList.toggle(“active”), e.submenuOne.classList.toggle(“active”); } else if (this.id === “WB18__nav–togglerTwo”) { !1 === e.cityListTwoOpen ? e.cityListTwoOpen = !0 : e.cityListTwoOpen = !1, e.togglerTwo.classList.toggle(“active”), e.submenuTwo.classList.toggle(“active”); } } e.cityListOneOpen = !1, e.togglerOne = document.querySelector(“#WB18__nav–togglerOne”), e.submenuOne = document.querySelector(“.WB18__nav–citylistOne”), e.togglerOne.addEventListener(“click”, t), e.addEventListener(“keyup”, function(n) { 27 === n.keyCode && !0 === e.cityListOneOpen && t() }), e.cityListTwoOpen = !1, e.togglerTwo = document.querySelector(“#WB18__nav–togglerTwo”), e.submenuTwo = document.querySelector(“.WB18__nav–citylistTwo”), e.togglerTwo.addEventListener(“click”, t), e.addEventListener(“keyup”, function(n) { 27 === n.keyCode && !0 === e.cityListTwoOpen && t() }) }(this);

Aerial view of Whitby, Ontario. (Town of Whitby)

25. Whitby, Ont.

Rank in 2017: 103
Population: 136,657
Estimated Unemployment Rate: 5.7%
Median Household Income: $101,792
Average Household Net Worth: $817,453
Property Tax: 11.1%
Total Days Above 20°C: 100
Crime Rate Per 100,000:* 3,251
Family Doctors Per 100,000:* 81
See more stats about Whitby, Ont. here.


(Town of New Tecumseth)

24. New Tecumseth, Ont.

Rank in 2017: 170
Population: 36,745
Estimated Unemployment Rate: 5.7%
Median Household Income: $96,041
Average Household Net Worth: $755,965
Property Tax: 20.5%
Total Days Above 20°C: 122
Crime Rate Per 100,000:* 2,906
Family Doctors Per 100,000:* 95
See more stats about New Tecumseth, Ont. here.


Jason Wighton/City of Newmarket

23. Newmarket, Ont.

Rank in 2017: 56
Population: 90,908
Estimated Unemployment Rate: 5.7%
Median Household Income: $95,636
Average Household Net Worth: $947,429
Property Tax: 16.1%
Total Days Above 20°C: 107
Crime Rate Per 100,000:* 2,749
Family Doctors Per 100,000:* 95
See more stats about Newmarket, Ont. here.


Brandon Born/Town of Bonnyville

22. Bonnyville No. 87, Alta.

Rank in 2017: 228
Population: 14,658
Estimated Unemployment Rate: 3.9%
Median Household Income: $103,652
Average Household Net Worth: $789,157
Property Tax: 94.0%
Total Days Above 20°C: 86
Crime Rate Per 100,000:* 4,899
Family Doctors Per 100,000:* 93
See more stats about Bonnyville No. 87, Alta. here.


St-Isidore in The Nation municipality of Ontario, Canada (P199/Wikipedia)

21. The Nation, Ont.

Rank in 2017: 123
Population: 13,275
Estimated Unemployment Rate: 5.1%
Median Household Income: $88,088
Average Household Net Worth: $478,620
Property Tax: 54.9%
Total Days Above 20°C: 113
Crime Rate Per 100,000:* 2,186
Family Doctors Per 100,000:* 142
See more stats about The Nation, Ont. here.


Whistler at night (David McColm/Tourism Whistler)

20. Whistler, B.C.

Rank in 2017: 84
Population: 13,193
Estimated Unemployment Rate: 4.3%
Median Household Income: $86,423
Average Household Net Worth: $1,460,422
Property Tax: 98.6%
Total Days Above 20°C: 83
Crime Rate Per 100,000:* 14,137
Family Doctors Per 100,000:* 159
See more stats about Whistler, B.C. here.


Downtown St. Albert

19. St. Albert, Alta.

Rank in 2017: 7
Population: 70,874
Estimated Unemployment Rate: 6.8%
Median Household Income: $123,948
Average Household Net Worth: $900,192
Property Tax: 66.3%
Total Days Above 20°C: 84
Crime Rate Per 100,000:* 5,313
Family Doctors Per 100,000:* 129
See more stats about St. Albert, Alta. here.


(City of King)

18. King, Ont.

Rank in 2017: 68
Population: 26,697
Estimated Unemployment Rate: 5.7%
Median Household Income: $110,816
Average Household Net Worth: $2,655,435
Property Tax: 18.1%
Total Days Above 20°C: 114
Crime Rate Per 100,000:* 2,749
Family Doctors Per 100,000:* 95
See more stats about King, Ont. here.


City of Levis

17. Lévis, Que.

Rank in 2017: 9
Population: 147,403
Estimated Unemployment Rate: 3.4%
Median Household Income: $79,323
Average Household Net Worth: $387,146
Property Tax: 65.1%
Total Days Above 20°C: 94
Crime Rate Per 100,000:* 2,784
Family Doctors Per 100,000:* 106
See more stats about Lévis, Que. here.


People skate at Nathan Phillips Square in Toronto, Ontario (Benson Kua/Wikipedia)

16. Toronto, Ont.

Rank in 2017: 129
Population: 2,933,262
Estimated Unemployment Rate: 5.7%
Median Household Income: $55,945
Average Household Net Worth: $906,663
Property Tax: 66.0%
Total Days Above 20°C: 117
Crime Rate Per 100,000:* 3,847
Family Doctors Per 100,000:* 75
See more stats about Toronto, Ont. here.


(City of Fort St. John)

15. Fort St. John, B.C.

Rank in 2017: 160
Population: 21,251
Estimated Unemployment Rate: 5.7%
Median Household Income: $106,327
Average Household Net Worth: $440,481
Property Tax: 99.5%
Total Days Above 20°C: 64
Crime Rate Per 100,000:* 14,000
Family Doctors Per 100,000:* 104
See more stats about Fort St. John, B.C. here.


(Town of Saugeen Shores)

14. Saugeen Shores, Ont.

Rank in 2017: 17
Population: 14,109
Estimated Unemployment Rate: 4.9%
Median Household Income: $105,210
Average Household Net Worth: $777,845
Property Tax: 14.2%
Total Days Above 20°C: 110
Crime Rate Per 100,000:* 5,113
Family Doctors Per 100,000:* 107
See more stats about Saugeen Shores, Ont. here.


Aerial view of Mount Royal (Photograph by Yves Tremblay – Photo HŽlico)

13. Mont-Royal, Que.

Rank in 2017: 8
Population: 21,172
Estimated Unemployment Rate: 6.3%
Median Household Income: $145,853
Average Household Net Worth: $2,392,238
Property Tax: 1.4%
Total Days Above 20°C: 117
Crime Rate Per 100,000:* 4,594
Family Doctors Per 100,000:* 124
See more stats about Mont-Royal, Que. here.


An aerial view of the city of Red Deer, Alberta. (Dwight Arthur/City of Red Deer)

12. Red Deer, Alta.

Rank in 2017: 330
Population: 107,564
Estimated Unemployment Rate: 4.9%
Median Household Income: $90,844
Average Household Net Worth: $628,900
Property Tax: 86.7%
Total Days Above 20°C: 83
Crime Rate Per 100,000:* 19,460
Family Doctors Per 100,000:* 99
See more stats about Red Deer, Alta. here.


11. Camrose, Alta.

Rank in 2017: 216
Population: 19,488
Estimated Unemployment Rate: 3.9%
Median Household Income: $61,873
Average Household Net Worth: $519,846
Property Tax: 74.9%
Total Days Above 20°C: 83
Crime Rate Per 100,000:* 9,520
Family Doctors Per 100,000:* 99
See more stats about Camrose, Alta. here.


(Town of Halton Hills)

10. Halton Hills, Ont.

Rank in 2017: 24
Population: 65,782
Estimated Unemployment Rate: 5.7%
Median Household Income: $108,410
Average Household Net Worth: $1,190,923
Property Tax: 24.3%
Total Days Above 20°C: 120
Crime Rate Per 100,000:* 2,133
Family Doctors Per 100,000:* 91
See more stats about Halton Hills, Ont. here.


Downtown Saint Lambert, Quebec (waferboard/Wikipedia)

9. Saint-Lambert, Que.

Rank in 2017: 55
Population: 22,432
Estimated Unemployment Rate: 4.9%
Median Household Income: $83,626
Average Household Net Worth: $881,272
Property Tax: 12.5%
Total Days Above 20°C: 118
Crime Rate Per 100,000:* 3,724
Family Doctors Per 100,000:* 96
See more stats about Saint-Lambert, Que. here.


Westmount, Quebec (City of Westmount)

8. Westmount, Que.

Rank in 2017: 52
Population: 21,083
Estimated Unemployment Rate: 7.5%
Median Household Income: $117,755
Average Household Net Worth: $3,953,205
Property Tax: 8.9%
Total Days Above 20°C: 117
Crime Rate Per 100,000:* 4,594
Family Doctors Per 100,000:* 124
See more stats about Westmount, Que. here.


(Nick Fox/Shutterstock)

7. Canmore, Alta.

Rank in 2017: 29
Population: 14,930
Estimated Unemployment Rate: 5.1%
Median Household Income: $75,848
Average Household Net Worth: $1,478,315
Property Tax: 99.0%
Total Days Above 20°C: 64
Crime Rate Per 100,000:* 7,482
Family Doctors Per 100,000:* 138
See more stats about Canmore, Alta. here.


Aerial view of Milton, Ontario (City of Milton)

6. Milton, Ont.

Rank in 2017: 151
Population: 120,556
Estimated Unemployment Rate: 5.7%
Median Household Income: $111,875
Average Household Net Worth: $1,129,276
Property Tax: 67.7%
Total Days Above 20°C: 120
Crime Rate Per 100,000:* 2,133
Family Doctors Per 100,000:* 91
See more stats about Milton, Ont. here.


Main Street in Lacombe, Alberta (Glen Larson/Wikipedia)

5. Lacombe, Alta.

Rank in 2017: 299
Population: 13,906
Estimated Unemployment Rate: 4.9%
Median Household Income: $97,800
Average Household Net Worth: $754,291
Property Tax: 76.6%
Total Days Above 20°C: 81
Crime Rate Per 100,000:* 7,932
Family Doctors Per 100,000:* 99
See more stats about Lacombe, Alta. here.


Vue aŽrienne (Photograph by Air Image)

4. Saint-Bruno-de-Montarville, Que.

Rank in 2017: 6
Population: 27,171
Estimated Unemployment Rate: 4.9%
Median Household Income: $96,757
Average Household Net Worth: $864,221
Property Tax: 18.8%
Total Days Above 20°C: 118
Crime Rate Per 100,000:* 3,724
Family Doctors Per 100,000:* 96
See more stats about Saint-Bruno-de-Montarville, Que. here.


(Sylvie Brault/Russell Township)

3. Russell, Ont.

Rank in 2017: 21
Population: 17,155
Estimated Unemployment Rate: 5.1%
Median Household Income: $112,644
Average Household Net Worth: $509,564
Property Tax: 50.1%
Total Days Above 20°C: 78
Crime Rate Per 100,000:* 2,540
Family Doctors Per 100,000:* 142
See more stats about Russell, Ont. here.


Parliament Hill in Ottawa, Ontario (Kovyrina/Shutterstock)

2. Ottawa, Ont.

Rank in 2017: 1
Population: 999,183
Estimated Unemployment Rate: 5.1%
Median Household Income: $93,975
Average Household Net Worth: $695,242
Property Tax: 39.3%
Total Days Above 20°C: 117
Crime Rate Per 100,000:* 3,782
Family Doctors Per 100,000:* 142
See more stats about Ottawa, Ont. here.


Aerial view of Oakville, Ontario (Town of Oakville)

1. Oakville, Ont.

Rank in 2017: 15
Population: 209,039
Estimated Unemployment Rate: 5.7%
Median Household Income: $112,207
Average Household Net Worth: $1,742,036
Property Tax: 21.4%
Total Days Above 20°C: 107
Crime Rate Per 100,000:* 2,133
Family Doctors Per 100,000:* 91
See more stats about Oakville, Ont. here.

*See the 2018 Canada’s Best Places to Live methodology for more details about this category.


.WB18{
box-sizing:border-box
}
.WB18 *{
box-sizing:inherit
}
.WB18 a{
transition-property:background-color,color;
transition-duration:.2s
}
.grid>div{
float:left
}
.grid{
display:flex;
flex-direction:column
}
.font__display–proxima{
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif
}
.font__display–jubilat{
font-family:jubilat,Georgia,serif
}
.WB18 h1,.WB18 h2,.WB18 h3,.WB18 h4,.WB18 h5,.WB18 h6{
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif;
font-weight:900
}
.WB18__header–wrap{
/*margin-bottom:2em */
}
.WB18__header{
display:block;
padding: 0;
text-align:center;
background-color:#2fbcf2;
color:#fff;
background-position:center center;
font-family:jubilat,Georgia,serif;
cursor:pointer
}
.WB18__header:hover{
color:#afeeee;
background-color:#29c4f2
}
.WB18__header span{
display:inline-block;
color:#dc1b1b;
transition-property:color;
transition-duration:.2s
}
.WB18__header span.to-animate{
animation-name:tada;
animation-duration:.9s;
animation-delay:1s
}
.WB18__header:hover span{
color:#dc143c
}
.WB18__header:hover span.label__year{
color:#444
}
.WB18__desktop {
display: none;
}
@media (min-width:768px){
.grid{
flex-direction:row
}
.grid>*{
padding-left:1em;
padding-right:1em;
flex-grow:1
}
.grid>:first-child{
margin-left:0
}
.grid>:last-child{
margin-right:0
}
.block{
width:100%
}
.WB18__header{
padding:0;
}
}
.WB18__headline,.single-post article h1.WB18__headline{
color:#fff
}
.WB18__header .label__year{
display:block;
position:absolute;
line-height:1em;
padding:.3em .8em .2em;
top:.25em;
right:.25em;
background-color:gold;
color:#444;
font-weight:900;
box-shadow:2px 2px 6px rgba(0,0,0,.5);
border-radius:20%/50%
}
.WB18__nav{
display:flex;
flex-wrap:wrap;
flex-direction:column;
margin:0;
background-color:#eee
}
@media (min-width:768px){
.WB18__header .label__year{
font-size:1.4em;
right:-.25em
}
.WB18__nav{
flex-direction:row;
justify-content:stretch
}
.WB18__nav a,.WB18__nav button{
/* flex-grow:1 */
flex-basis: 50%;
}
}
@media (min-width: 1264px){
.WB18__nav a,.WB18__nav button{
/* flex-grow:1 */
flex-basis: 25%;
}
}
.WB18__nav a,.WB18__nav button{
padding:1rem 0.8rem;
border:0;
text-align:left;
background-color:#eee;
color:#dc1b1b;
font-family:proxima-nova,”Helvetica Neue”,Helvetica,Arial,sans-serif
}
#WB18__nav–togglerOne.active,#WB18__nav–togglerTwo.active,.WB18__nav a:hover,.WB18__nav button:hover{
background-color:#29c4f2;
color:#fff
}
.WB18__nav–overview{
order:1
}
.WB18__nav–other{
order:2
}
#WB18__nav–togglerOne{
order:3
}
#WB18__nav–togglerTwo{
order:4
}
.WB18__nav button{
outline:0
}
.WB18__nav #WB18__nav–togglerOne,.WB18__nav #WB18__nav–togglerTwo{
position:relative;
z-index:20
}
.WB18__nav #WB18__nav–togglerOne::after,.WB18__nav #WB18__nav–togglerTwo::after{
display:inline-block;
padding:0 1rem;
content:’ 025BE’;
transition-property:transform;
transition-duration:.2s
}
.WB18__nav #WB18__nav–togglerOne.active::after,.WB18__nav #WB18__nav–togglerTwo.active::after{
content:’ 025BE’;
transform:rotate(180deg)
}
.WB18__nav–citylistOne,.WB18__nav–citylistTwo{
position:absolute;
display:flex;
width:100%;
z-index:10;
flex-direction:column;
transform:translateX(-999em);
box-shadow:0 6px 4px rgba(0,0,0,.5)
}
.WB18__nav–citylistOne.active,.WB18__nav–citylistTwo.active{
transform:translateX(0);
z-index:20
}
.WB18__nav–citylistOne a,.WB18__nav–citylistTwo a{
background-color:#29c4f2;
color:#eee
}
.WB18__nav–citylistOne a:hover,.WB18__nav–citylistTwo a:hover{
background-color:#444;
color:#eee
}
@media (min-width:768px){
.WB18__nav–overview{
order:1
}
.WB18__nav–other{
order:4
}
#WB18__nav–togglerOne{
order:2
}
#WB18__nav–togglerTwo{
order:3
}
.WB18__mobile {
display: none;
}
.WB18__desktop {
display: block;
}
}
@keyframes tada{
from,to{
–transform:scale3d(1,1,1);
transform:scale3d(1,1,1)
}
10%,20%{
–transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);
transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)
}
30%,50%,70%,90%{
–transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);
transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)
}
40%,60%,80%{
–transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);
transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)
}
}

! function(e, t) { “object” == typeof exports && “object” == typeof module ? module.exports = t() : “function” == typeof define && define.amd ? define([], t) : “object” == typeof exports ? exports.inView = t() : e.inView = t() }(this, function() { return function(e) { function t(i) { if (n[i]) return n[i].exports; var r = n[i] = { exports: {}, id: i, loaded: !1 }; return e[i].call(r.exports, r, r.exports, t), r.loaded = !0, r.exports } var n = {}; return t.m = e, t.c = n, t.p = “”, t(0) }([function(e, t, n) { “use strict”; var i, r = n(2), o = (i = r) && i.__esModule ? i : { default: i }; e.exports = o.default }, function(e, t) { e.exports = function(e) { var t = typeof e; return null != e && (“object” == t || “function” == t) } }, function(e, t, n) { “use strict”; function i(e) { return e && e.__esModule ? e : { default: e } } Object.defineProperty(t, “__esModule”, { value: !0 }); var r = i(n(9)), o = i(n(3)), u = n(4); t.default = function() { if (“undefined” != typeof window) { var e = { history: [] }, t = { offset: {}, threshold: 0, test: u.inViewport }, n = (0, r.default)(function() { e.history.forEach(function(t) { e[t].check() }) }, 100); [“scroll”, “resize”, “load”].forEach(function(e) { return addEventListener(e, n) }), window.MutationObserver && addEventListener(“DOMContentLoaded”, function() { new MutationObserver(n).observe(document.body, { attributes: !0, childList: !0, subtree: !0 }) }); var i = function(n) { if (“string” == typeof n) { var i = [].slice.call(document.querySelectorAll(n)); return e.history.indexOf(n) > -1 ? e[n].elements = i : (e[n] = (0, o.default)(i, t), e.history.push(n)), e[n] } }; return i.offset = function(e) { if (void 0 === e) return t.offset; var n = function(e) { return “number” == typeof e }; return [“top”, “right”, “bottom”, “left”].forEach(n(e) ? function(n) { return t.offset[n] = e } : function(i) { return n(e[i]) ? t.offset[i] = e[i] : null }), t.offset }, i.threshold = function(e) { return “number” == typeof e && e >= 0 && e <= 1 ? t.threshold = e : t.threshold }, i.test = function(e) { return "function" == typeof e ? t.test = e : t.test }, i.is = function(e) { return t.test(e, t) }, i.offset(0), i } }() }, function(e, t) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var n = function() { function e(e, t) { for (var n = 0; n -1, o = !n && r; n && !r && (e.current.push(t), e.emit(“enter”, t)), o && (e.current.splice(i, 1), e.emit(“exit”, t)) }), this } }, { key: “on”, value: function(e, t) { return this.handlers[e].push(t), this } }, { key: “once”, value: function(e, t) { return this.singles[e].unshift(t), this } }, { key: “emit”, value: function(e, t) { for (; this.singles[e].length;) this.singles[e].pop()(t); for (var n = this.handlers[e].length; –n > -1;) this.handlers[e][n](t); return this } }]), e }(); t.default = function(e, t) { return new i(e, t) } }, function(e, t) { “use strict”; Object.defineProperty(t, “__esModule”, { value: !0 }), t.inViewport = function(e, t) { var n = e.getBoundingClientRect(), i = n.top, r = n.right, o = n.bottom, u = n.left, c = n.width, s = n.height, f = o, a = window.innerWidth – u, l = window.innerHeight – i, d = r, p = t.threshold * c, h = t.threshold * s; return f > t.offset.top + h && a > t.offset.right + p && l > t.offset.bottom + h && d > t.offset.left + p } }, function(e, t) { (function(t) { var n = “object” == typeof t && t && t.Object === Object && t; e.exports = n }).call(t, function() { return this }()) }, function(e, t, n) { var i = n(5), r = “object” == typeof self && self && self.Object === Object && self, o = i || r || Function(“return this”)(); e.exports = o }, function(e, t, n) { var i = n(1), r = n(8), o = n(10), u = “Expected a function”, c = Math.max, s = Math.min; e.exports = function(e, t, n) { function f(t) { var n = h, i = v; return h = v = void 0, w = t, m = e.apply(i, n) } function a(e) { var n = e – b; return void 0 === b || n >= t || n = y } function l() { var e, n, i = r(); return a(i) ? d(i) : void(g = setTimeout(l, (e = i, n = t – (e – b), x ? s(n, y – (e – w)) : n))) } function d(e) { return g = void 0, T && h ? f(e) : (h = v = void 0, m) } function p() { var e, n = r(), i = a(n); if (h = arguments, v = this, b = n, i) { if (void 0 === g) return e = b, w = e, g = setTimeout(l, t), O ? f(e) : m; if (x) return g = setTimeout(l, t), f(b) } return void 0 === g && (g = setTimeout(l, t)), m } var h, v, y, m, g, b, w = 0, O = !1, x = !1, T = !0; if (“function” != typeof e) throw new TypeError(u); return t = o(t) || 0, i(n) && (O = !!n.leading, y = (x = “maxWait” in n) ? c(o(n.maxWait) || 0, t) : y, T = “trailing” in n ? !!n.trailing : T), p.cancel = function() { void 0 !== g && clearTimeout(g), w = 0, h = b = v = g = void 0 }, p.flush = function() { return void 0 === g ? m : d(r()) }, p } }, function(e, t, n) { var i = n(6); e.exports = function() { return i.Date.now() } }, function(e, t, n) { var i = n(7), r = n(1), o = “Expected a function”; e.exports = function(e, t, n) { var u = !0, c = !0; if (“function” != typeof e) throw new TypeError(o); return r(n) && (u = “leading” in n ? !!n.leading : u, c = “trailing” in n ? !!n.trailing : c), i(e, t, { leading: u, maxWait: t, trailing: c }) } }, function(e, t) { e.exports = function(e) { return e } }]) }), function(e, t) { if (“function” == typeof define && define.amd) define([“module”, “exports”], t); else if (“undefined” != typeof exports) t(module, exports); else { var n = { exports: {} }; t(n, n.exports), e.fitty = n.exports } }(this, function(e, t) { “use strict”; Object.defineProperty(t, “__esModule”, { value: !0 }); var n = Object.assign || function(e) { for (var t = 1; t 1 && void 0 !== arguments[1] ? arguments[1] : {}; return “string” == typeof e ? t(r(document.querySelectorAll(e)), n) : t([e], n)[0] } if (e) { var r = function(e) { return [].slice.call(e) }, o = { IDLE: 0, DIRTY_CONTENT: 1, DIRTY_LAYOUT: 2, DIRTY: 3 }, u = [], c = null, s = “requestAnimationFrame” in e ? function() { e.cancelAnimationFrame(c), c = e.requestAnimationFrame(function() { a(u.filter(function(e) { return e.dirty })) }) } : function() {}, f = function(e) { return function() { u.forEach(function(t) { t.dirty = e }), s() } }, a = function(e) { e.filter(function(e) { return !e.styleComputed }).forEach(function(e) { e.styleComputed = p(e) }), e.filter(h).forEach(y), e.filter(d).forEach(l), e.forEach(v), e.forEach(m) }, l = function(e) { e.availableWidth = e.element.parentNode.clientWidth, e.currentWidth = e.element.scrollWidth, e.previousFontSize = e.currentFontSize, e.currentFontSize = Math.min(Math.max(e.minSize, e.availableWidth / e.currentWidth * e.previousFontSize), e.maxSize), e.whiteSpace = e.multiLine && e.currentFontSize === e.minSize ? “normal” : “nowrap” }, d = function(e) { return e.dirty !== o.DIRTY_LAYOUT || e.dirty === o.DIRTY_LAYOUT && e.element.parentNode.clientWidth !== e.availableWidth }, p = function(t) { var n = e.getComputedStyle(t.element, null); t.currentFontSize = parseInt(n.getPropertyValue(“font-size”), 10), t.display = n.getPropertyValue(“display”), t.whiteSpace = n.getPropertyValue(“white-space”) }, h = function(e) { var t = !1; return /inline-/.test(e.display) || (t = !0, e.display = “inline-block”), “nowrap” !== e.whiteSpace && (t = !0, e.whiteSpace = “nowrap”), t }, v = function(e) { y(e), e.dirty = o.IDLE }, y = function(e) { e.originalStyle || (e.originalStyle = e.element.getAttribute(“style”) || “”), e.element.style.cssText = e.originalStyle + “;white-space:” + e.whiteSpace + “;display:” + e.display + “;font-size:” + e.currentFontSize + “px” }, m = function(e) { e.element.dispatchEvent(new CustomEvent(“fit”, { detail: { oldValue: e.previousFontSize, newValue: e.currentFontSize, scaleFactor: e.currentFontSize / e.previousFontSize } })) }, g = function(e, t) { return function() { e.dirty = t, s() } }, b = function(e) { e.newbie = !0, e.dirty = !0, u.push(e) }, w = function(e) { return function() { u = u.filter(function(t) { return t.element !== e.element }), e.observeMutations && e.observer.disconnect(), e.element.style.cssText = e.originalStyle } }, O = function(e) { e.observeMutations && (e.observer = new MutationObserver(g(e, o.DIRTY_CONTENT)), e.observer.observe(e.element, e.observeMutations)) }, x = { minSize: 16, maxSize: 512, multiLine: !0, observeMutations: “MutationObserver” in e && { subtree: !0, childList: !0, characterData: !0 } }, T = null, L = function() { e.clearTimeout(T), T = e.setTimeout(f(o.DIRTY_LAYOUT), i.observeWindowDelay) }, S = [“resize”, “orientationchange”]; return Object.defineProperty(i, “observeWindow”, { set: function(t) { var n = (t ? “add” : “remove”) + “EventListener”; S.forEach(function(t) { e[n](t, L) }) } }), i.observeWindow = !0, i.observeWindowDelay = 100, i.fitAll = f(o.DIRTY), i } }(“undefined” == typeof window ? null : window), e.exports = t.default }), fitty(“.fit”), inView(“.fit”).on(“enter”, function() { fitty(“.fit”) }), function(e) { function t() { if (this.id === “WB18__nav–togglerOne”) { !1 === e.cityListOneOpen ? e.cityListOneOpen = !0 : e.cityListOneOpen = !1, e.togglerOne.classList.toggle(“active”), e.submenuOne.classList.toggle(“active”); } else if (this.id === “WB18__nav–togglerTwo”) { !1 === e.cityListTwoOpen ? e.cityListTwoOpen = !0 : e.cityListTwoOpen = !1, e.togglerTwo.classList.toggle(“active”), e.submenuTwo.classList.toggle(“active”); } } e.cityListOneOpen = !1, e.togglerOne = document.querySelector(“#WB18__nav–togglerOne”), e.submenuOne = document.querySelector(“.WB18__nav–citylistOne”), e.togglerOne.addEventListener(“click”, t), e.addEventListener(“keyup”, function(n) { 27 === n.keyCode && !0 === e.cityListOneOpen && t() }), e.cityListTwoOpen = !1, e.togglerTwo = document.querySelector(“#WB18__nav–togglerTwo”), e.submenuTwo = document.querySelector(“.WB18__nav–citylistTwo”), e.togglerTwo.addEventListener(“click”, t), e.addEventListener(“keyup”, function(n) { 27 === n.keyCode && !0 === e.cityListTwoOpen && t() }) }(this);

The post Canada’s Top 25 Best Places to Live in 2018 appeared first on MoneySense.



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *